ComunidadBóvedaWhatsApp AgentKit

WhatsApp AgentKit

El kit casi no tiene código, y ese es el punto: el código te lo escribe Claude Code en tu computadora, durante una entrevista de diez preguntas. Esta guía te lleva de cero a un número de WhatsApp contestando solo, con trece prompts listos para pegar.

De qué va

Clonas el kit, corres la entrevista y Claude Code te deja el agente completo en tu máquina.

Lo que bajas son diecinueve archivos y casi ninguno es código. El grueso es un solo documento que le dice a Claude Code qué construir: la carpeta del agente, sus dependencias y su Dockerfile no están en GitHub a propósito, y aparecen en tu computadora cuando corres la entrevista.

Necesitas cuatro cosas: Python 3.11 o superior, Claude Code, una llave de Anthropic y una cuenta de WhatsApp API — Zernio o Meta, y aquí te decimos cuál te toca. Docker no hace falta: el servidor construye la imagen del lado de ellos.

No hay que leer ni escribir una línea de Python. Cada vez que hay que tocar código, el tramo trae el prompt que le pegas a Claude Code para que lo haga él, y el comando con el que compruebas tú que quedó.

Si lo que buscas no es un agente que conteste sino uno que además califique al cliente, agende y escriba en tu CRM, eso es otra guía y es bastante más larga: el AgentKit que cierra ventas. El de aquí conversa, entiende y deja los datos en el historial; hacer cosas por ti es un cableado aparte que se explica al final.

IntermedioTrece promptsMIT · PythonZernio o MetaDocker opcional

El repo

Hainrixz/whatsapp-agentkit

Python, licencia MIT y 494 estrellas. Son diecinueve archivos y casi ninguno es código: «este repo casi no tiene código», dice su propio sitio, porque lo que hay adentro son las instrucciones con las que Claude Code te escribe el agente en tu máquina.

Las dieciséis secciones

01 · el resultado

Qué vas a tener al final

Un número que contesta solo, y lo que tu agente no hace.

02 · lo que hace falta

Las cuatro cosas que necesitas

Python, Claude Code, la llave de Anthropic y una cuenta de WhatsApp API.

03 · la llave

La llave de Anthropic, clic por clic

Dónde se saca, cómo empieza y por qué solo se ve una vez.

04 · elegir camino

Zernio o Meta: cuál te toca

Una tabla y un criterio. Se elige una sola vez y no hay que volver atrás.

05 · Zernio

Zernio, clic por clic

La cuenta, la llave, el secreto del webhook y el número de pruebas.

06 · Meta

Meta Cloud API, clic por clic

La app de Facebook, los cuatro datos y el App Secret que está escondido.

07 · bajar el kit

Tres comandos y ya estás adentro

Qué hace start.sh de verdad, y qué no hace aunque el README diga que sí.

08 · la entrevista

/build-agent y las diez preguntas

Las diez, con la que más rinde marcada, y qué archivos quedan al terminar.

09 · probarlo

Probarlo en tu compu

Las dos pruebas locales y los tres estados del chequeo de salud.

10 · a tu GitHub

Los dos pasos que casi todos se saltan

El remote heredado y el .gitignore que deja fuera justo lo que hay que subir.

11 · Railway

De tu GitHub a internet

Proyecto, base de datos, variables y el dominio que no se genera solo.

12 · el webhook

Decirle a WhatsApp a dónde avisar

El alta, la firma, los cinco segundos y los siete reintentos.

13 · cuando algo falla

Síntoma, causa, arreglo

Las fallas reales de este kit, cada una con su arreglo de una línea.

14 · personalizarlo

Cambiarle cosas, y el límite real

Tono, conocimiento, cambiar de proveedor, y cablear de verdad una herramienta.

15 · los números

Lo que cuesta, con fecha

El modelo, el servidor y WhatsApp. Por qué sube la cuenta y cómo se baja.

16 · preguntas

Preguntas frecuentes

Lo que se pregunta cuando ya está corriendo y aparece la primera duda.

Ficha

WhatsApp AgentKit, de un vistazo

Nivel
Intermedio. Copias comandos y haces clics en dos paneles; no escribes código.
Temas
WhatsApp API, Claude Code, Zernio o Meta, webhooks, Railway y PostgreSQL.
Qué necesitas
Python 3.11 o superior, Claude Code, una llave de Anthropic y una cuenta de WhatsApp API. Docker no hace falta.
Cuánto toma
Una sesión sin prisa: la entrevista son diez preguntas y lo demás son clics. Lo que tarde de verdad depende del proveedor que elijas.

01 · el resultado

Qué vas a tener al final, y qué no hace todavía

Antes de instalar nada conviene saber exactamente qué compras con la sesión que estás por empezar. Esta sección es eso: lo que te queda funcionando, lo que no, y cuál de las tres guías de WhatsApp de la bóveda es la tuya.

en una frase

Un número de WhatsApp que contesta solo, con la información de tu negocio, y que se acuerda de cada cliente entre un día y otro.

Tu cliente escribe a las once de la noche y le responde tu agente con tus precios, tu horario y tus condiciones, no con generalidades de internet.

Y si vuelve mañana no empieza de cero: antes de responder, tu agente lee el historial de esa conversación. Es un número, no una app que alguien tenga que descargar.

el dato que nadie espera

El kit casi no tiene código, y es a propósito

Lo que te bajas de GitHub son diecinueve archivos y casi ninguno es programa. El que manda es CLAUDE.md: ochenta kilobytes de instrucciones escritas para que las lea Claude Code, no tú.

El sitio del proyecto lo dice con todas sus letras: «Este repo casi no tiene código».

Lo que no vas a encontrar en GitHub es justamente lo que hace funcionar a tu agente:

  • agent/ — el programa que recibe los mensajes y responde.
  • config/ — el prompt del sistema y los datos de tu negocio.
  • tests/ — las pruebas con las que compruebas que quedó.
  • requirements.txt — la lista de lo que hay que instalar.
  • Dockerfile y docker-compose.yml — cómo se empaqueta para subirlo.

Nada de eso está en el repositorio: el .gitignore del kit lo excluye a propósito. Aparece en tu computadora cuando corres la entrevista, y lo escribe Claude Code con las respuestas que tú le des. Por eso dos personas que clonen el mismo kit terminan con dos agentes distintos.

Tres negocios, tres agentes distintos

El mismo kit, respondiendo con lo que tú le hayas dado. Lo que cambia entre uno y otro no es el programa: es lo que contestaste en la entrevista y los archivos de tu negocio que le dejaste a mano.

restaurante

El que contesta el menú

  • Cuánto cuesta la pizza grande y qué trae.
  • A qué hora abren el domingo.
  • Qué hay sin gluten y cuáles son las opciones.

clínica o salón

El que contesta servicios y horarios

  • Qué servicios hay y cuánto dura cada uno.
  • Cuánto cuesta la limpieza y qué incluye.
  • Qué días de la semana atiende cada persona.

inmobiliaria

El que filtra antes de que llames

  • Qué hay en esa zona y en qué rango de precio.
  • Si aceptan mascotas y cuánto piden de depósito.
  • Deja escritos en el historial el presupuesto y la zona que pidió el cliente.

Qué pasa entre que tu cliente escribe y le llega la respuesta

Seis pasos. No hace falta que los entiendas para usar el kit, pero el día que algo falle vas a saber en cuál de los seis mirar.

un mensaje, de punta a punta

1  Tu cliente escribe. El mensaje llega al
   proveedor (Zernio o Meta).

2  El proveedor se lo manda a tu servidor
   por el webhook.

3  Tu servidor verifica la firma y
   descarta el aviso si ya lo había
   recibido antes.

4  Contesta 200 de inmediato y sigue
   trabajando por su cuenta.

5  Busca el historial de esa conversación
   y se lo manda a Claude junto con el
   mensaje y la información de tu negocio.

6  Claude escribe la respuesta y se envía
   de vuelta por WhatsApp.

Lo que tu agente todavía no hace solo

lo que todavía no hace solo

agent/tools.py se genera, pero no se ejecuta

Claude Code escribe ese archivo con funciones de verdad —reservar una cita, agregar al carrito, registrar un lead— y ahí se quedan: ningún módulo las importa y nunca llegan a Claude.

Lo que tu agente sí hace: conversa, entiende y te deja los datos en el historial. Si tu cliente dice «quiero el martes a las cinco», eso queda escrito y tú lo lees.

Lo que todavía no hace solo: agendar esa cita, cobrarla o descontar stock. Eso es un cableado aparte.

Que sepa tu menú no depende de ese archivo: la información de tu negocio le llega por el prompt del sistema. tools.py hace falta para hacer, no para contestar.

Ese cableado se puede hacer y no lo tienes que escribir tú: el apartado de personalizar trae el prompt que conecta una de esas funciones de punta a punta. Pero es un paso más, y no viene hecho.

Si esta no era tu guía

En la bóveda hay tres caminos para poner un agente en WhatsApp y se parecen poco entre sí. Este es el corto: una entrevista y ya.

WhatsApp AgentKit (esta)

Cuándo es la tuya
Quieres un número que conteste solo, con la información de tu negocio, y lo quieres esta semana. Nivel intermedio.
Qué te cuesta de más
Casi nada, y ese es el punto. A cambio, tu agente conversa y entiende: hacer cosas por ti se cablea aparte.

El AgentKit que cierra ventas

Cuándo es la tuya
La venta se cierra por chat y necesitas calificar al cliente, agendar y que quede escrito en tu CRM. Nivel avanzado.
Qué te cuesta de más
Quince fases en vez de una entrevista, modo borrador para revisar antes de mandar y una compuerta de veintitrés chequeos.

OpenWA, el camino del QR

Cuándo es la tuya
No quieres pasar por Meta ni por un proveedor: escaneas un código con tu propio WhatsApp. Nivel avanzado.
Qué te cuesta de más
Lo hospedas tú y lo mantienes tú. Es el camino con más piezas propias de los tres.

La que cierra ventas es el AgentKit que cierra ventas, y ahí viven también los plazos de verificación de negocio en Meta.

La del código QR es OpenWA, WhatsApp sin Meta: lo hospedas tú, sin proveedor de por medio.

02 · lo que hace falta

Las cuatro cosas que necesitas

Cuatro para construir tu agente, y dos de ellas se instalan con un comando cada una. Conviene tenerlas antes de empezar, porque el kit revisa dos de las cuatro apenas arranca y se detiene ahí mismo si le falta alguna.

Cada una hace algo distinto y ninguna sustituye a otra: Python es lo que corre tu agente, Claude Code es lo que lo escribe, la llave de Anthropic es lo que lo hace pensar y la cuenta de WhatsApp API es por donde entran y salen los mensajes.

Más adelante vas a abrir dos cuentas más —GitHub en la sección 10 y Railway en la 11—, pero esas se crean sobre la marcha, cuando toque subir tu agente y ponerlo en internet. Hoy no te hacen falta.

1

Python 3.11 o superior

Es el lenguaje en el que va a estar escrito tu agente, y el que lo mantiene encendido cuando llega un mensaje. La versión no es un detalle: por debajo de 3.11 el kit no arranca.

Según tu sistema:

  • Mac: brew install python en la Terminal.
  • Windows: descarga el instalador y marca la casilla "Add to PATH" durante la instalación.
  • Linux: sudo apt install python3.11

El instalador de Windows se baja de python.org, y esa casilla es la que evita que después el comando de abajo no exista.

2

Node.js LTS y Claude Code

Claude Code es quien escribe el agente: tú no vas a leer ni escribir una línea de Python. Se instala con npm, que viene dentro de Node.js, así que Node va primero, en su versión LTS.

Si no lo tienes, se baja de nodejs.org. El comando de Claude Code está justo debajo de esta lista.

3

La llave de Anthropic

Es lo que hace que tu agente piense: cada respuesta que escribe pasa por ahí.

No la saques todavía. De dónde se saca, cómo empieza y por qué solo se ve una vez está en el paso siguiente, clic por clic.

4

Una cuenta de WhatsApp API

Es por donde entran y salen los mensajes. Hay dos caminos, Zernio o Meta Cloud API, y se toma uno solo.

Cuál te toca es la única decisión de fondo de esta guía y se resuelve dos secciones más abajo, con una tabla y un criterio. Se elige una vez y no hay que volver atrás.

Revisa Python antes de bajar nada

Puede que ya lo tengas puesto. Abre la Terminal, pega esto y mira qué te contesta:

Ver si ya tienes Python

python3 --version

Si responde un número igual o mayor a 3.11 —3.11, 3.12, 3.13—, ya está: no instales nada.

Si responde un número menor, o si te dice que no conoce el comando, instálalo con la ruta de tu sistema y vuelve a correr esta misma línea hasta que el número te cuadre.

Instalar Claude Code, y autenticarlo una vez

Con Node puesto, Claude Code se instala con un comando. Va en la misma Terminal y da igual en qué carpeta estés parado:

Instalar Claude Code

npm install -g @anthropic-ai/claude-code

Falta el paso que casi todo el mundo se salta. Cuando termine de instalar, escribe claude a secas y deja que abra sesión con tu cuenta. Se hace una sola vez y sin eso la herramienta queda instalada pero muda.

Recién cuando claude abre sin pedirte nada conviene seguir al paso de bajar el kit. Ahí se revisa que esté a la mano, y si no lo está el arranque se corta y te pide justo este comando.

lo que NO necesitas

Tres cosas que la gente cree que hacen falta

  • Docker. No lo instalas ni ahora ni después: el servidor donde va a vivir tu agente construye la imagen del lado de ellos.
  • Tarjeta para probarlo. Si vas por Zernio, la cuenta se abre en el plan gratis sin tarjeta y el número de pruebas no cuesta.
  • Saber programar. Tú pegas comandos, haces clics y contestas diez preguntas; leer y escribir Python es trabajo de Claude Code.

Lo único que se paga por uso es lo que tu agente le pregunta a Claude. Cuánto, con números y con fecha, está al final, en la cuenta completa.

03 · la llave

Sacar tu API key de Anthropic, clic por clic

Tu agente le habla a Claude por su cuenta, a las tres de la mañana y sin que tú estés adelante. Para eso necesita una llave propia: un texto largo que Anthropic te entrega una sola vez y que tu servidor presenta cada vez que tiene que pensar una respuesta.

Sacarla son cinco clics y no llega a dos minutos. El único que hay que hacer con cuidado es el último, porque la llave se muestra una vez y después esa pantalla ya no vuelve.

Todo pasa en la consola de Anthropic, que no es la misma página donde chateas con Claude: platform.anthropic.com. Ese enlace te deja directo en la pantalla de las llaves.

Los cinco clics, en orden

1

Abre platform.anthropic.com

La consola de Anthropic. Es una puerta distinta a la de la app y a la de Claude Code, aunque todo sea de la misma casa.

2

Crea la cuenta, o entra con la que ya tienes

Si es tu primera vez en la consola, ahí mismo la creas. Tener Claude Code pagado no te salta este paso: son dos cosas separadas.

3

Settings, y ahí dentro API Keys

Settings es la configuración de la consola, y adentro está la sección API Keys. Los dos rótulos están en inglés.

4

Create Key

El botón que la crea. Ahí nace la llave, y nace lista para usarse.

5

Cópiala en ese momento

Empieza con sk-ant-. La vas a necesitar en un rato, cuando corras la entrevista, así que cópiala completa antes de cerrar nada.

la pantalla que no vuelve

Si no la copiaste, no la busques

Anthropic te muestra la llave completa una sola vez, en la pantalla donde nace. Cuando la cierras no hay un «ver de nuevo» escondido en algún menú: no existe.

Tampoco es un drama. Vuelves a Settings → API Keys → Create Key y sacas otra. Lo que se pierde es el minuto, nada más.

cómo sabes que es la buena

Cómo reconoces que tienes la llave correcta

empieza con
sk-ant-
dónde se saca
platform.anthropic.com → Settings → API Keys → Create Key
cuántas veces se ve
Una. Si la pierdes, no se recupera: se crea otra.
en qué variable va
ANTHROPIC_API_KEY
dónde termina
En el archivo .env de tu carpeta. Ese archivo se queda en tu computadora y nunca sube a GitHub.
qué no es
Tu suscripción de Claude Code. Son dos cuentas distintas y cada una se cobra por su lado.

la regla que no se rompe

La llave va en un solo lugar y en ninguno más

No se pega en un chat, ni en un issue de GitHub, ni en una captura de pantalla para pedir ayuda. Quien la vea puede gastar con tu cuenta, y ese consumo se cobra en la tuya.

Su lugar es el archivo .env de tu carpeta, y nada más. Ese archivo no sube a GitHub.

Si se te escapó en alguno de esos lugares, dala por perdida: vuelve a Create Key, saca otra y usa la nueva.

No es lo mismo que tu suscripción de Claude Code

Son dos cuentas con el mismo apellido. La suscripción es para que trabajes tú, con Claude Code abierto en tu computadora. La llave es para que trabaje tu agente, solo, desde el servidor, mientras tú haces otra cosa.

Por eso tener Claude Code pagado no te ahorra la llave, y tener la llave no te da Claude Code. La llave se factura aparte y por uso: pagas por lo que tu agente conversa, no una mensualidad fija.

Cuánto es ese uso —por modelo, por conversación y al mes— está en la sección 15, con su fecha. Los números viven ahí y solo ahí, con el día en que se consultó cada tarifa.

Qué modelo usa tu agente, y cómo se cambia

De fábrica tu agente piensa con claude-sonnet-5. Si quieres otro, no hay que abrir un archivo de código ni entender Python: se cambia el valor de una variable y ya.

Estas son las cuatro que tocan a Anthropic. La primera es la llave que acabas de sacar; las otras tres traen un valor por defecto que ya funciona.

ANTHROPIC_API_KEY

La que acabas de copiar, tal cual, empezando por sk-ant-. No hay dónde volver a verla: si la perdiste, saca otra desde Create Key.

ANTHROPIC_MODELOpcional, con matiz
claude-sonnet-5

El modelo con el que piensa tu agente. Las tres opciones son claude-opus-5, claude-sonnet-5 y claude-haiku-4-5, y cambiarlo es reemplazar este texto por el otro.

ANTHROPIC_EFFORTOpcional, con matiz
low

Cuánto se detiene a pensar antes de contestar: low, medium o high. Si la dejas vacía, el parámetro ni se envía, que es justo lo que hay que hacer con los modelos viejos, porque no lo aceptan.

ANTHROPIC_MAX_TOKENSOpcional, con matiz
4096

El largo máximo de cada respuesta. Viene comentada en el archivo. Cuidado con bajarla: lo que el modelo piensa por dentro también cuenta contra ese tope, así que un número chico corta las respuestas a la mitad.

Si no escribes ninguna de las tres opcionales, tu agente arranca con esos mismos valores.

04 · elegir camino

Zernio o Meta: cuál te toca

Tu agente necesita una puerta por la que entren y salgan los mensajes de WhatsApp. Hay dos, y elegir es la única decisión de la guía que conviene tomar antes de escribir nada. Tranquilo, que no es cara: al final de la sección está qué pasa si eliges mal.

Qué es cada uno

Zernio corre sobre la WhatsApp Cloud API de Meta. No la reemplaza: se para encima y te resuelve las tres partes que más tardan. El Embedded Signup —la ventana de Meta donde eliges o creas tu cuenta de WhatsApp Business y su número, sin salir de ahí—, un inbox donde ves las conversaciones, y webhooks firmados, que es lo que hace que tu agente pueda distinguir un aviso legítimo de uno inventado. No tienes que crear una app de Facebook ni pasar App Review.

Meta Cloud API directo es conectarte tú, sin nadie en medio. Creas una app de Facebook tipo Business, le agregas el producto de WhatsApp, generas tus propias credenciales y das de alta el webhook con tus manos. Nada de eso es difícil: son más pasos, y uno de ellos —App Review— lo revisa Meta y no depende de ti.

Las cuatro diferencias

Esta tabla es del propio kit. Léela por la columna que te interese y fíjate menos en qué camino es «mejor» que en cuál de los dos te pide cosas que hoy no tienes:

App de Facebook

Zernio
No hace falta
Meta Cloud API directo
Sí, tipo Business

App Review

Zernio
No
Meta Cloud API directo
Sí

Verificación de negocio

Zernio
Desde el Embedded Signup
Meta Cloud API directo
Cuenta de Facebook Business verificada

Probar sin número propio

Zernio
Sí, número compartido
Meta Cloud API directo
Sí, pero antes hay que crear la app

Ninguna fila habla de dinero, y es a propósito: lo que cuesta cada camino va junto con el resto de los números, en la sección de costos.

el criterio

Una línea y ya elegiste

Si ya tienes tu app de Facebook tipo Business armada y verificada, ve por Meta: el trabajo duro ya lo hiciste.

Si no la tienes, ve por Zernio y te ahorras crear la app y pasar App Review.

Se elige una vez, en la pregunta 9

Esta decisión no se declara en ningún archivo ni se configura dos veces. La entrevista te lo pregunta —es la pregunta 9 de las diez—, y con esa respuesta Claude Code escribe solo el adaptador del que elegiste.

Si eliges Zernio, el archivo que habla con Meta ni siquiera se escribe. Y al revés. Así que cuando mires tu carpeta vas a ver un proveedor y no dos: no es que falte algo, es que lo otro nunca llegó a existir.

la regla de las 24 horas

Lo que WhatsApp te deja mandar, y cuándo

WhatsApp solo permite texto libre —lo que tu agente escriba, con sus propias palabras— dentro de las 24 horas posteriores al último mensaje del cliente. Ese contador se reinicia cada vez que el cliente te vuelve a escribir.

Fuera de esa ventana el texto libre no sale. Lo único que puedes mandar es una plantilla aprobada por Meta: un mensaje escrito de antemano, enviado a revisión y autorizado antes de poder usarlo.

La buena noticia es que este agente siempre responde. Alguien le escribe, él contesta, y eso ocurre siempre dentro de las 24 horas. En la práctica nunca sale de la ventana y nunca vas a necesitar una plantilla.

Dónde sí importa: el día que quieras que tu agente escriba primero —un recordatorio, una promoción, un seguimiento a quien te dejó en visto—, eso ya es otra cosa, y esa sí pide plantilla aprobada.

¿Y si eliges mal?

No pasa nada, y no tienes que volver a empezar. El prompt del sistema con los datos de tu negocio, lo que le cargaste de tu catálogo y el historial de conversaciones no dependen del proveedor: sobreviven al cambio.

Migrar de uno a otro es pedírselo a Claude Code en una frase y darle las credenciales del nuevo.

La frase exacta, con lo que hay que decirle para no perder nada en el camino, está en cambiarle cosas, y el límite real.

05 · Zernio

Crear la cuenta, conectar WhatsApp y sacar la API key

Zernio corre sobre la WhatsApp Cloud API de Meta: pone de su lado el alta con Meta, la bandeja de conversaciones y los avisos firmados. Eso es exactamente lo que te ahorra crear una app de Facebook y pasar por App Review.

De esta sección te llevas dos valores y nada más: la API key, que te la enseña el panel una sola vez, y el secreto del webhook, que no está en ninguna pantalla porque lo inventas tú. Con esos dos, y con el número de pruebas encendido, puedes ver a tu agente contestando el mismo día.

La ruta del panel, tal cual, sin desvíos

1

Crea la cuenta en zernio.com

El plan Free no pide tarjeta. Con eso alcanza para todo lo que hace esta guía, incluido el número de pruebas.

2

Connections → Connect new → WhatsApp

Está en el panel, en el menú lateral. «Connect new» abre la lista de canales; el que buscas es WhatsApp.

3

Completa el Embedded Signup de Meta

Se abre una ventana de Meta dentro del panel. Ahí eliges o creas la cuenta de WhatsApp Business y el número. No sales de Zernio y no creas ninguna app de Facebook.

4

Settings → API Keys → Create API Key

Otra vez en el menú lateral, ya no en Connections. El botón está arriba de la lista de llaves.

5

Cópiala en ese momento

Es el paso que más gente pierde. Pégala en tu gestor de contraseñas antes de cerrar el aviso; después no hay dónde volver a verla.

6

Inventa el secreto del webhook

No lo busques en el panel. Elige una cadena larga y al azar, como una contraseña, y guárdala junto a la llave.

7

El webhook, todavía no

Ese paso pide la dirección pública de tu agente, que aún no existe. Queda pendiente y se retoma más adelante.

cópiala ahora

La API key se muestra una sola vez

Cuando le das a Create API Key, el panel te la enseña en esa pantalla y no vuelve a enseñártela. Si cierras la ventana sin copiarla, no hay «verla de nuevo»: vuelves a Settings → API Keys → Create API Key, sacas otra y usas esa.

La reconoces por la forma: empieza con sk_ y sigue con 64 caracteres hexadecimales, o sea números y letras de la a a la f. Si lo que pegaste no empieza con sk_, copiaste otra cosa.

Su lugar final es la variable ZERNIO_API_KEY de tu archivo .env. Mientras tanto, guárdala donde guardas contraseñas y no la pegues en un chat.

el secreto lo inventas tú

El secreto del webhook no te lo da Zernio

Es el único dato de esta sección que no sale de una pantalla: lo eliges tú. Y sirve para una cosa muy concreta: comprobar que cada aviso que llega viene de Zernio y no de cualquiera que haya adivinado la dirección de tu agente.

Va a estar escrito en dos lados y tiene que ser el mismo texto exacto en los dos: en tu archivo .env, como ZERNIO_WEBHOOK_SECRET, y en el alta del webhook dentro del panel de Zernio. Si difieren en un carácter, los avisos legítimos se caen.

El alta del webhook no se hace aquí, y no es por orden de lectura: hace falta la dirección pública de tu agente y todavía no existe. Va en la sección del webhook, cuando ya esté desplegado. Por ahora basta con tener el secreto escrito y a mano.

Los dos valores, con el nombre que van a llevar

Estos son los nombres exactos con los que vas a ver escritos tus dos datos. No tienes que abrir ningún archivo a mano: Claude Code te los pide de a uno y los escribe él.

ZERNIO_API_KEY

La que copiaste en Settings → API Keys. Empieza con sk_ y sigue con 64 caracteres hexadecimales. Aquí no hay valor de ejemplo porque es tuya y no se comparte con nadie.

ZERNIO_WEBHOOK_SECRET

La cadena que inventaste tú. El mismo texto exacto va después en el alta del webhook, dentro del panel de Zernio, y de ahí sale la comprobación de que un aviso es legítimo.

El número de pruebas: para qué sirve y para qué no

Zernio presta un número compartido para que veas tu agente andando antes de tener uno propio. Se enciende abriendo una sesión contra tu celular: te llega un WhatsApp con una plantilla llamada sandbox_start y tienes que responderlo desde tu teléfono. Ese «responder» es lo que abre la sesión, y sin él no pasa nada más.

sirve para

Verlo funcionando hoy

  • Comprobar que tu agente recibe, entiende y contesta, sin esperar a tener un número propio.
  • Probar el tono y las respuestas con tu celular y con el de dos o tres personas de confianza.
  • Cerrar el circuito completo y verlo: llega el mensaje, tu agente responde, lo lees en WhatsApp.

no sirve para

Atender clientes

  • Atender de verdad: los cupos diarios se agotan con un puñado de conversaciones.
  • Dejarlo puesto y olvidarte, porque la sesión vence y hay que volver a abrirla.
  • Escribirle tú primero a alguien que no haya respondido la plantilla de arranque.

el número de pruebas, en números

Los cupos, tal como están hoy

Mensajes
50 cada 24 horas.
Destinatarios
5 distintos cada 24 horas.
Sesiones
Una sola activa a la vez.
Sesión pendiente
Caduca a las 24 horas si nadie responde la plantilla.
Sesión activada
Dura 7 días.

Cupos verificados el 17 de septiembre de 2026.

Enciéndelo sin escribir un solo comando

Un detalle que te va a confundir si miras la documentación: para listar los números, la doc de Zernio dice GET /v1/phone-numbers y el documento del kit dice /api/v1/whatsapp/phone-numbers. No tienes que elegir a ciegas, y el prompt tampoco: prueba las dos y se queda con la que responda.

Prompt 01 · Encender el número de pruebas

Córrelo cuando ya tengas el kit y tu llave escrita en el .env. Claude Code hace las llamadas; lo único tuyo es responder el WhatsApp que te va a llegar.

Quiero ver mi agente andando en WhatsApp hoy, con el número de pruebas de Zernio. Hazlo tú de punta a punta.

CONTEXTO:
- Mi llave de Zernio ya está en el .env de esta carpeta, en la variable ZERNIO_API_KEY. Léela de ahí. No me la pidas por chat.
- Base de la API: https://zernio.com/api/v1. La autenticación va en Authorization: Bearer con esa llave.
- Para listar los números hay dos rutas en circulación: la doc dice GET /v1/phone-numbers y el CLAUDE.md del kit dice /api/v1/whatsapp/phone-numbers. Prueba las dos y usa la que responda.
- Mi celular con WhatsApp, con código de país: [ESCRIBE AQUÍ: +52 55 1234 5678]

OBJETIVO:
Dejar una sesión del número de pruebas activa contra mi celular, confirmada por la API y no por lo que supones.

QUÉ HACER, EN ESTE ORDEN:
1. Descubre el número de pruebas con la ruta que te responda.
2. Abre la sesión con POST /v1/whatsapp/sandbox/sessions y mi celular.
3. Avísame, antes de seguir, que me va a llegar un WhatsApp con la plantilla sandbox_start y que tengo que RESPONDERLO desde mi celular. Espera a que yo confirme que respondí.
4. Consulta el estado de la sesión hasta que la API diga que está activa.

RESTRICCIONES DURAS:
- NUNCA imprimas mi ZERNIO_API_KEY, ni entera ni en pedazos.
- NO abras la sesión contra un número que no sea el que te di.
- NO abras una segunda sesión: solo se permite una activa a la vez.
- NO me digas que quedó activado si la API no lo confirmó.

CRITERIO DE ACEPTACIÓN, compruébalo tú:
- La ruta de números respondió 200 y trajo un número.
- El estado de la sesión dice que está activa.
- Ninguna salida que me muestres contiene la llave.

QUÉ REPORTAR AL FINAL:
Qué ruta funcionó, el estado de la sesión, y mis tres límites: 50 mensajes y 5 destinatarios distintos cada 24 horas, y que la sesión activada dura 7 días.

Dos cosas antes de seguir. El prompt de aquí arriba no se corre ahora: pide el kit ya bajado y tu llave ya escrita en el .env, que son las secciones 07 y 08. Vuelve por él cuando el chequeo de salud de la sección 09 te conteste ok, y ahí sí vas a ver a tu agente contestando en WhatsApp.

Y si te quedaste con Zernio, la sección de Meta no te toca: sáltatela entera y sigue con la que baja el kit a tu computadora.

06 · Meta

Los cuatro datos que te va a pedir Meta

Son cuatro datos, y viven en dos pantallas distintas del panel de desarrolladores. Dos los copias, uno te lo inventas tú y el cuarto está escondido detrás de un botón que dice Show.

Ninguno se escribe a mano en un archivo: los dejas donde los tengas a la vista y la entrevista te los va a pedir de a uno. Lo único que pide cuidado es el sexto paso, porque ese texto lo eliges tú y tiene que quedar idéntico en dos lugares.

Todo pasa en un solo panel: developers.facebook.com. Antes de empezar, ten abierto dónde vas a pegar los cuatro valores.

La ruta, en este orden

1

Abre developers.facebook.com

Es el panel de desarrolladores de Meta. Desde ahí se crea todo lo demás.

2

Crea una app de tipo Business

Meta te pide elegir un tipo cuando creas la app. El que va aquí es Business.

3

Agrégale el producto WhatsApp

Dentro de tu app, en la lista de productos. A partir de ahí tienes el menú de WhatsApp.

4

WhatsApp → API Setup: copia el Phone Number ID

Ojo con este: no es el número de teléfono. Es un id numérico, y es lo que le dice a Meta desde qué número sale cada respuesta.

5

En la misma pantalla, genera un token de acceso permanente

Hay uno de 24 horas para probar rápido y hay uno permanente. El que va aquí es el permanente, y abajo te digo qué pasa si guardas el otro.

6

Inventa el Verify Token

Este no te lo da Meta ni te lo da nadie: es un texto que eliges tú. El kit sugiere agentkit-verify.

Anótalo tal cual lo escribiste. Va en dos lugares y tienen que ser el mismo texto exacto.

7

Settings → Basic → App Secret → clic en Show

Está tapado hasta que lo pides. Es con lo que tu agente comprueba que cada mensaje que le llega viene de verdad de Meta.

el token que muerde

Tiene que ser el permanente

Si guardas el de 24 horas, todo funciona hoy y mañana tu agente se queda mudo: sigue recibiendo mensajes y ya no puede contestar ninguno.

El síntoma es tramposo porque no se cae nada. El chequeo de salud contesta 200 y queda en degradado, con el detalle de la credencial rechazada adentro.

Genera el permanente desde el principio y guárdalo donde no se te pierda: esa pantalla no te lo vuelve a mostrar en bandeja.

Los cuatro datos, uno por uno

META_ACCESS_TOKEN

De dónde sale
WhatsApp → API Setup, generando el token permanente.
Para qué lo usa el agente
Enviar. Es lo que autoriza cada mensaje que sale de tu agente hacia Meta.

META_PHONE_NUMBER_ID

De dónde sale
WhatsApp → API Setup.
Para qué lo usa el agente
Decir desde qué número sale la respuesta. No es el número de teléfono: es un id numérico.

META_VERIFY_TOKEN

De dónde sale
Lo inventas tú. El kit sugiere agentkit-verify.
Para qué lo usa el agente
El apretón de manos de una sola vez, cuando das de alta el webhook. Después no se vuelve a usar.

META_APP_SECRET

De dónde sale
Settings → Basic → App Secret, clic en Show.
Para qué lo usa el agente
Verificar la firma de cada mensaje que entra, uno por uno.

Ninguno de los cuatro impide que tu agente arranque, y por eso hay que ponerlos bien desde el principio: si el token está mal, el chequeo de salud queda en degradado; si falta el App Secret, arranca, acepta todo lo que le llegue y solo lo avisa en los registros.

Los dos valores que se escriben tal cual

De todo lo de arriba, estos dos son los únicos que puedes ver escritos aquí. Los otros dos son tuyos y no se publican en ninguna página.

META_VERIFY_TOKEN
agentkit-verify

Lo inventas tú; este es el que sugiere el kit y sirve perfecto. Va idéntico, letra por letra, en tus variables y en la casilla de Meta cuando des de alta el webhook.

META_API_VERSIONOpcional, con matiz
v25.0

Ya viene puesta: es la versión de la Graph API con la que tu agente le habla a Meta. Solo se toca si Meta deprecó esa versión.

el 403 que es correcto

Si el verify token no coincide, tu servidor dice que no

Al dar de alta el webhook, Meta llama una sola vez a tu URL con hub.mode=subscribe y el texto que escribiste en la casilla.

Si ese texto no es idéntico al de META_VERIFY_TOKEN, tu servidor devuelve 403. A propósito, y está bien que lo haga.

Devolver 200 ahí le haría creer a Meta que la URL quedó verificada cuando no lo está: te quedarías con un alta que se ve bien y no te entrega un solo mensaje.

El arreglo es aburrido: el mismo texto exacto en los dos lados y vuelves a lanzar la verificación.

La firma viene en otro encabezado

Cada aviso que Meta le manda a tu agente viene firmado, y esa firma viaja en el encabezado X-Hub-Signature-256, con el formato sha256=<hex>. Zernio firma lo mismo, pero en otro encabezado y sin ese prefijo, así que el código que comprueba una de las dos firmas no sirve para la otra.

Por eso Claude Code escribe un adaptador distinto para cada proveedor, y por eso en la entrevista se elige uno solo: el archivo del otro ni se genera.

Los dos encabezados, lado a lado

Meta     X-Hub-Signature-256: sha256=<hex>
Zernio   X-Zernio-Signature: <hex>

Dónde se pega la URL, qué casillas se llenan y por qué hay cinco segundos de por medio va completo en el capítulo del webhook. Aquí solo importaba de dónde sale el App Secret con el que se comprueba esa firma.

Las dos puertas de este camino

Además de los cuatro datos, Meta te pone dos puertas por delante. Ninguna se salta, y ninguna la pone el kit.

  • Una cuenta de Facebook Business verificada.
  • Pasar App Review.

Cuánto tardan esas dos puertas no lo vas a leer aquí con un número inventado: los plazos viven, fechados y con su fuente, en el AgentKit que cierra ventas. Si al llegar hasta aquí descubres que tu cuenta todavía no está verificada, esa guía es la que te dice qué sigue.

Con esos cuatro datos guardados terminas aquí. El número de pruebas de la sección 05 no te toca: ese es de Zernio, y si te la saltaste hiciste bien.

Por este camino vas a ver a tu agente contestar primero en tu computadora, en la sección 09, y por WhatsApp solo cuando des de alta el webhook, en la 12. Ahora sigue con la sección que baja el kit.

07 · bajar el kit

Tres comandos y ya estás adentro

Tres comandos en la terminal y el kit queda en tu computadora. Van en este orden y de uno en uno; el tercero es el único que hace algo, y aun así no instala nada: solo revisa que tengas lo necesario y deja la carpeta en su sitio.

Abre la terminal y pega el primero tal cual, sin cambiar de carpeta: el kit se baja donde la terminal te deja al abrirla, que es tu carpeta de usuario, y desde ahí funciona igual. Cuando termine vas a tener una carpeta nueva llamada whatsapp-agentkit, y los otros dos se corren ya adentro de ella.

1 · Bajar el kit a tu compu

git clone https://github.com/Hainrixz/whatsapp-agentkit.git

2 · Entrar a la carpeta

cd whatsapp-agentkit

3 · Preparar el entorno

bash start.sh

Qué hace y qué no hace start.sh

Cuatro cosas, y ninguna es instalar dependencias

  • Revisa que tengas Python 3.11 o superior. Si falta o es menor, se detiene ahí mismo.
  • Revisa que el comando claude esté disponible. Si no lo está, se detiene y te deja escrita la línea de npm que lo instala.
  • Crea la carpeta knowledge/, que es donde después van los archivos de tu negocio.
  • Copia .env.example a .env, y solo si .env no existía. Si ya lo tenías, no lo toca.

Eso es todo. Lo que no hace, aunque el README diga que sí, es instalar las dependencias de Python: ese paso ocurre más adelante y lo hace Claude Code por su cuenta, no tú.

Así que si el script termina rápido y sin descargar nada, no se saltó nada. Terminó.

Y si se corta, es por una de dos cosas, las dos de la sección lo que hace falta: o Python no llega a 3.11, o Claude Code no está instalado. Lo resuelves ahí, vuelves a esta carpeta y corres bash start.sh otra vez. No pasa nada por correrlo dos veces.

Cómo sabes que salió bien

Los cuatro chequeos, en el orden en que corren

[1/4] Python 3.11 o superior: listo
[2/4] Claude Code en el PATH: listo
[3/4] Carpeta knowledge/: creada
[4/4] .env creado a partir de .env.example

Cuatro pasos y te devuelve el control de la terminal. El texto exacto lo pone el script y puede cambiar; lo que no cambia es el orden. Si se detiene antes de llegar al cuarto, el motivo queda escrito en la línea donde paró: no hay que ir a buscarlo a ningún registro.

Abrir Claude Code sin salir de la carpeta

Un comando más, y este cambia con quién estás hablando: hasta aquí le hablabas a la terminal, de aquí en adelante le hablas a Claude Code.

Tiene que abrirse dentro de whatsapp-agentkit, porque lo que ve es lo que hay en la carpeta desde donde lo abriste. Si lo abres en otro lado, no encuentra el kit.

Abrir Claude Code en esa carpeta

claude

Prompt 02 · El mapa del terreno, antes de la entrevista

Pégalo apenas abra Claude Code, antes de escribir /build-agent. Le dice qué hay en la carpeta y qué falta a propósito. Sin esto, lo más común es que se ponga a buscar el código del agente y te avise de que el repositorio está incompleto, que es justo lo que no pasa.

Acabo de clonar este repositorio y voy a construir mi agente de WhatsApp contigo. Antes de arrancar, ubícate.

CONTEXTO, y esto es lo importante:
- Este repositorio NO contiene el agente. Contiene las instrucciones con las que tú lo escribes, y CLAUDE.md es ese sistema entero.
- Por eso agent/, config/, tests/, requirements.txt, Dockerfile y docker-compose.yml todavía no existen, y está bien que no existan: los vas a escribir tú. No me reportes que faltan.
- Lo único que hay son 19 archivos: CLAUDE.md, README.md, start.sh, scripts/audit.py, .env.example y la carpeta .claude/, entre otros.
- Yo no programo: no me muestres diffs ni me pidas editar archivos a mano.

OBJETIVO:
Que quedes ubicado y que yo sepa qué viene, antes de /build-agent.

QUÉ HACER, EN ESTE ORDEN:
1. Lee CLAUDE.md completo, de principio a fin.
2. Corre `python3 --version` y dime qué versión hay.
3. Comprueba que existe .env en la raíz. Si no existe, créalo copiando .env.example, sin escribir ningún valor adentro.
4. Explícame en español simple, en diez líneas como máximo: qué archivos vas a escribir, en qué carpetas van a quedar y cuánto dura la entrevista.

RESTRICCIONES DURAS:
- NO ejecutes /build-agent todavía. Espera a que yo te lo pida.
- NO modifiques CLAUDE.md, README.md, start.sh ni .gitignore.
- NO inventes credenciales ni pongas valores de ejemplo en .env.
- NO instales nada sin avisarme antes qué es y para qué sirve.

CRITERIO DE ACEPTACIÓN, compruébalo tú antes de decir que acabaste:
- `python3 --version` imprime 3.11 o superior.
- `ls .env` muestra el archivo en la raíz de la carpeta.
Si alguno falla, dime en español qué falta y cómo lo consigo, y no sigas.

QUÉ REPORTAR AL FINAL:
La versión de Python, si .env ya existía o lo creaste tú, y tu resumen de diez líneas.

Cuando te conteste con ese resumen de diez líneas, ya estás listo para la entrevista, que es el tramo que sigue.

08 · la entrevista

La entrevista: las diez preguntas que construyen tu agente

Hasta aquí juntaste piezas. Este es el tramo donde se construye el agente, y se construye contestando preguntas en español: diez, una por una, sin un solo archivo que abrir ni una línea que escribir.

Claude Code lee el documento del kit, te entrevista y va escribiendo los archivos conforme le respondes. Ninguno de esos archivos existía cuando clonaste.

Arrancar la entrevista

/build-agent

Ojo con dónde se escribe: eso no es un comando de la terminal. Primero entras a Claude Code —escribes claude y das enter—, y una vez adentro escribes la diagonal y el nombre en su caja de mensajes. Si lo pegas en la terminal a secas, te va a decir que el comando no existe.

A partir de ahí no te apures: se puede contestar con frases largas y desordenadas. Lo que Claude Code no puede es adivinar lo que no le digas.

Las diez preguntas, y qué decide cada respuesta

No son un formulario: cada respuesta aterriza en un archivo concreto o cambia lo que se va a escribir. Esta es la traducción, pregunta por pregunta.

1

Cómo se llama tu negocio

Queda en config/business.yaml, el archivo donde vive la información de tu negocio.

2

A qué se dedica: qué vendes, qué servicios das, quiénes son tus clientes

Esta es la que arma el prompt del sistema, o sea la instrucción permanente que Claude recibe en cada turno de cada conversación. Mientras más concreta sea tu respuesta, menos genérico suena tu agente.

3

Para qué lo quieres

Seis opciones numeradas: 1 responder preguntas frecuentes, 2 agendar citas, 3 captar clientes y vender, 4 tomar pedidos, 5 dar soporte, 6 otro.

Esta decide qué funciones se escriben en agent/tools.py: agendar deja reservar_cita y cancelar_cita, pedidos deja agregar_al_carrito y confirmar_pedido, y así. Se escriben, pero no se ejecutan solas: conectarlas de verdad es la sección 14.

4

Cómo se llama tu agente

El nombre con el que se presenta ante tus clientes, no el de la carpeta. Viaja al prompt del sistema junto con lo de la pregunta 2.

5

Qué tono quieres

Cuatro opciones: 1 profesional y formal, 2 amigable y casual, 3 vendedor y persuasivo, 4 empático y cálido.

Es lo que hace que suene a tu negocio y no a un manual. También va al prompt del sistema.

6

Tu horario de atención

Es lo que contesta cuando le preguntan si estás abierto. Además queda como una de las funciones que se generan listas, obtener_horario().

7

¿Tienes archivos? Menú, precios, preguntas frecuentes, catálogo, políticas

Lo que entregues aquí se guarda en la carpeta knowledge/ y es la pregunta que más cambia el resultado. Va aparte, abajo.

8

Tu llave de Anthropic

La que sacaste en la sección 03, la que empieza con sk-ant-. Queda en el archivo de configuración, nunca dentro del código.

9

Zernio o Meta

La decisión ya la tomaste en la sección 04 y aquí solo se declara. Claude Code escribe el adaptador de la que elijas y nada más: no genera los dos para que escojas después.

10

Las credenciales del proveedor que elegiste

Con Zernio son dos datos; con Meta, cuatro. Los tienes de la sección 05 o de la 06, según el camino que te tocó. El prompt del final de esta sección te los pide de a uno y los deja donde van.

la pregunta que más rinde

La 7 es la que separa un agente tuyo de un agente cualquiera

Lo que pongas en knowledge/ se incorpora textualmente al prompt del sistema. La instrucción del sistema es no resumir de más: los precios y las condiciones quedan literales, con su número y su letra chica, no convertidos en «tenemos precios accesibles».

Si tu archivo es grande, prioriza lo que un cliente preguntaría por WhatsApp —cuánto cuesta, si hay disponibilidad, si entregan a domicilio, qué incluye— y deja fuera lo que nadie pregunta por ahí. Eso también te sale más barato: todo lo que metas al prompt del sistema se reenvía en cada turno.

Sobre el formato: el .gitkeep de la carpeta nombra .txt, .md y .csv, y la pregunta 7 acepta además PDF, DOCX, imágenes y JSON. Usa texto plano, que es lo que seguro se lee.

Tres cosas que puedes dejar de cuidar

  • Tus llaves nunca terminan escritas dentro del código: van al archivo de configuración, y antes de sobrescribir algo que ya esté en config/ o en las credenciales, Claude Code te pregunta.
  • Las dependencias de Python no las instalas tú: mientras corre la entrevista, Claude Code escribe requirements.txt con la lista completa y las instala con pip. Ese es el «más adelante» que anuncia la sección 07.
  • Y si te interrumpen a la mitad, no se pierde: el avance queda guardado en config/session.yaml. Vuelves a abrir Claude Code, le dices que retome la entrevista y sigue donde se quedó.

lo que queda en tu carpeta al terminar

whatsapp-agentkit/
├── agent/              lo que contesta
├── config/             tu negocio y tono
├── knowledge/          tus archivos
├── tests/              las dos pruebas
├── requirements.txt    lo que se instala
├── Dockerfile          cómo se construye
├── docker-compose.yml  todo junto, local
├── .dockerignore       lo que no entra
└── .env                llaves: no se sube

Salvo knowledge/, que ya venía vacía en el clon, nada de eso estaba en GitHub, y no es un descuido: el kit lo excluye a propósito porque es tuyo, no suyo. Si al terminar te falta alguno, la entrevista no llegó hasta el final.

Prompt 03 · Las credenciales, una por una

Pégalo en Claude Code cuando la entrevista llegue a las preguntas 8, 9 y 10. Te las pide de a una, las deja donde van y te avisa si algo quedó a medias.

Configura las credenciales de mi agente. Hazlo tú; yo te las paso.

CONTEXTO:
- Estoy dentro de la carpeta del kit. start.sh ya creó el archivo .env a partir de .env.example: es el único que se toca aquí.
- Es para la prueba local, no para un servidor.
- El proveedor que ya elegí: [ESCRIBE AQUÍ: zernio o meta]

OBJETIVO:
Que la configuración quede lista para arrancar en mi computadora, sin un valor inventado.

QUÉ HACER, EN ESTE ORDEN:
1. Pídeme las credenciales UNA POR UNA y espera mi respuesta antes de pedir la siguiente. No me mandes una lista.
2. Pon WHATSAPP_PROVIDER con el proveedor que te di, en minúsculas.
3. ZERNIO_WEBHOOK_SECRET y META_VERIFY_TOKEN los invento yo. Pídemelos igual y avísame que ESE MISMO texto va después en el alta del webhook.
4. Deja PORT=8000, ENVIRONMENT=development y DATABASE_URL en SQLite: sqlite+aiosqlite:///./agentkit.db
5. Borra o comenta TODAS las variables del proveedor que NO elegí.
6. Que no quede ZERNIO_BASE_URL declarada y vacía: una URL sin https:// hace que el envío falle antes de salir a la red.

RESTRICCIONES DURAS:
- NUNCA escribas una credencial mía en el chat ni en un commit.
- NO inventes valores. Si falta uno, detente y pídemelo.
- NO agregues variables que no estén en .env.example.
- NO toques .gitignore aquí.

CRITERIO DE ACEPTACIÓN, compruébalo tú antes de decir que acabaste:
- `grep -c "^WHATSAPP_PROVIDER=" .env` devuelve 1.
- Ninguna obligatoria del proveedor que elegí quedó vacía.
- No queda ZERNIO_BASE_URL con valor vacío y sin comentar.
- `git check-ignore .env` confirma que está ignorado.
Si alguno falla, arréglalo y vuelve a comprobar.

QUÉ REPORTAR AL FINAL:
Los NOMBRES de las variables que quedaron puestas y de las que comentaste —nunca sus valores— y cada criterio de arriba, uno por línea.

09 · probarlo

Hablar con tu agente antes de que hable un cliente

Ya tienes tu agente en la carpeta. Antes de subirlo a internet hay dos pruebas, y hay que hacer las dos: una revisa que conteste bien y la otra que el servidor levante. Son cosas distintas y una puede pasar con la otra rota.

Las dos corren en tu computadora. No hace falta WhatsApp, ni webhook, ni dominio: nadie de afuera puede escribirle todavía, así que es el momento de equivocarse.

Prueba 1 — háblale tú, desde la terminal

Las dos pruebas van en la terminal, no dentro de Claude Code: si lo dejaste abierto desde la entrevista, ciérralo y vuelve a la terminal, o abre una ventana nueva y entra a la carpeta con cd whatsapp-agentkit. El primer comando abre un chat ahí mismo. Le escribes como si fueras un cliente y te contesta como le contestaría a un cliente: con el tono que elegiste en la entrevista y con lo que dejaste en knowledge/.

Prueba 1 · el chat en la terminal

python tests/test_local.py

conversación de prueba

Tú: hola, ¿están abiertos hoy?
Agente: Hola. Hoy atendemos de 9 a 19 h.

Tú: ¿cuánto cuesta el corte?
Agente: Corte 250 pesos. Con barba, 350.

Tú: ¿aceptan tarjeta?
Agente: Sí, y transferencia o efectivo.

Eso es todo lo que hace, y es exactamente lo que quieres ver antes que un cliente: si aquí se inventa un precio, en WhatsApp se lo inventa igual.

Gasta de verdad

No es un simulador

Cada respuesta de esta prueba es un mensaje real al modelo y sale de tu llave de Anthropic, igual que si te hubiera escrito un cliente. Probar diez veces cuesta como diez conversaciones.

Cuánto es eso en dinero, con fecha y por modelo, está en lo que cuesta.

Prueba 2 — que el servidor levante

La segunda prueba no habla con nadie. Solo comprueba que el programa arranca y que puede decirte cómo se siente. Deja esta terminal corriendo: mientras el comando esté vivo, el servidor está de pie.

Prueba 2 · levanta el servidor

uvicorn agent.main:app --reload --port 8000

Ahora abre otra terminal —la primera quedó ocupada— y pregúntale a tu agente cómo está. Eso es el chequeo de salud:

El chequeo de salud

curl http://localhost:8000/

Los tres estados, y dónde está el detalle de cada uno

Ese comando devuelve una línea de texto con un campo llamado «status». Tiene tres valores posibles, y cada uno se arregla en un lugar distinto. Esta es la tabla que vas a volver a mirar cuando ya esté en internet:

"status":"ok"

Qué significa
Arrancó y las credenciales del proveedor respondieron.
Dónde mirar el detalle
—

"status":"degradado"

Qué significa
Arrancó, pero el proveedor no contestó bien: va a recibir mensajes y no va a poder responderlos.
Dónde mirar el detalle
Dentro de conexion.detalle

"status":"error"

Qué significa
Ni siquiera pudo armar el proveedor: falta WHATSAPP_PROVIDER o está mal escrita.
Dónde mirar el detalle
En detalle, en la raíz

lo que devuelve el chequeo de salud

si arrancó (ok o degradado):
{"status":"degradado",
 "service":"agentkit",
 "proveedor":"ProveedorZernio",
 "conexion":{"ok":false,"detalle":"..."}}

si no pudo ni armar el proveedor:
{"status":"error",
 "service":"agentkit",
 "detalle":"<el error>"}

Por eso la tercera columna de la tabla: el detalle de «degradado» viene metido dentro de conexion, y el de «error» va suelto arriba del todo. Si buscas en el lugar equivocado, parece que no dice nada.

Por qué siempre contesta 200

El código de respuesta no te sirve aquí

Ese chequeo devuelve 200 aunque las credenciales estén mal, y es a propósito. Si contestara con un error, Railway daría el despliegue por caído y lo reiniciaría sin parar, y tú nunca alcanzarías a leer el diagnóstico.

Así que el 200 no es la buena noticia. La buena noticia es el campo «status». Un agente con la llave del proveedor rechazada contesta 200 y dice «degradado», y va a recibir mensajes que no va a poder responder.

Si no te gusta cómo contesta

Nada de esto se arregla tocando código. Le dices a Claude Code qué te chirría —que se alarga, que saluda raro, que no menciona el horario— y él ajusta config/prompts.yaml, que es donde vive la personalidad de tu agente.

Qué se puede cambiar, hasta dónde, y qué cosas no se arreglan con el prompt está en cambiarle cosas, y el límite real.

La puerta

No sigas con esto en rojo

Si en tu computadora no contesta, en internet tampoco. Lo único que cambia allá es que se suman el webhook, el dominio y las variables del panel: tres cosas nuevas que pueden fallar encima de la que ya está fallando.

La regla es corta. Hasta que el chat de prueba sostenga una conversación y el chequeo de salud diga «ok», no se pasa a la siguiente sección.

Prompt 04 · Probar el agente en tu computadora

Corre las dos pruebas, traduce el chequeo de salud al español y repite hasta que diga ok.

Prueba mi agente en mi computadora y tradúceme el resultado.

CONTEXTO:
- Estoy en la carpeta del kit. La entrevista ya corrió: existen agent/, config/, tests/ y mi .env.
- No hay webhook ni servidor público: esto es local.
- Yo no leo Python. Explícame en español y sin jerga.

OBJETIVO:
Que las dos pruebas locales pasen y que yo entienda el resultado.

QUÉ HACER, EN ESTE ORDEN:
1. Corre `python tests/test_local.py` y mándale tres mensajes como si fueras un cliente mío.
2. Levanta el servidor con `uvicorn agent.main:app --reload --port 8000`.
3. En otra terminal corre `curl http://localhost:8000/` y léeme el campo "status", no el código HTTP.
4. Traduce ese campo con esta regla, exacta:
- "ok": arrancó y las credenciales del proveedor respondieron.
- "degradado": el proveedor no contestó bien. Lee conexion.detalle, dime qué variable falta o qué credencial rechazaron, y corrígela.
- "error": no pudo ni armar el proveedor. Lee detalle en la raíz y revisa WHATSAPP_PROVIDER: va zernio o meta, en minúsculas.
5. Si no dio "ok", arréglalo y repite desde el paso 2 hasta que diga "ok".

RESTRICCIONES DURAS:
- NO me digas "responde 200, todo bien": este servidor contesta 200 a propósito aunque las credenciales estén mal. Vale el campo "status".
- NO toques config/prompts.yaml sin preguntarme antes.
- NO cambies el modelo para ahorrar: esa decisión es mía.
- NO borres ni reescribas mi .env.

CRITERIO DE ACEPTACIÓN, compruébalo tú:
- `python tests/test_local.py` sostiene una charla de tres turnos.
- `curl http://localhost:8000/` devuelve "status":"ok".
Si falla alguno, arréglalo y vuelve a comprobar antes de decirme que terminaste.

QUÉ REPORTAR AL FINAL:
La conversación completa, el "status" que salió, qué significa, y qué tocaste.

10 · a tu GitHub

Mandarlo a tu GitHub: los dos pasos que casi todos se saltan

Tu agente ya contesta en tu computadora. Para que conteste cuando tu computadora está apagada tiene que vivir en un servidor, y el camino a ese servidor pasa por un repositorio tuyo en GitHub. Son dos pasos y los dos tienen trampa: el primero te va a fallar con un error que parece grave y no lo es, y el segundo no falla — que es peor, porque sube un repositorio incompleto sin decirte nada.

Ninguno de los dos pide entender git. Piden saber que existen.

por qué te va a fallar el comando que buscaste en Google

Estás parado dentro de un repositorio que no es tuyo

Cuando clonaste el kit no bajaste una carpeta de archivos: bajaste el repositorio de git completo, con su historial y con un remote llamado origin que apunta al repo público de AgentKit.

Por eso las dos recetas que salen primero cuando buscas «subir mi proyecto a GitHub» no aplican aquí. git init no va, porque el repositorio ya existe. Y git remote add origin aborta antes de hacer nada:

lo que ves en la terminal

$ git remote add origin https://github.com/TU-USUARIO/mi-agente.git
error: remote origin already exists.

No rompiste nada. Git te está avisando que ese nombre ya está ocupado por el repositorio ajeno. Se suelta el heredado, se pone el tuyo, y sigues. Lo que nunca va aquí es git init.

Los tres pasos, en orden

1

Crea el repositorio en GitHub, y créalo vacío

En github.com/new. Sin README, sin .gitignore y sin licencia: las tres casillas se dejan en blanco. Todo lo que va a subir ya lo tienes en tu computadora.

2

Reemplaza el .gitignore antes de empujar

Este es el paso que casi nadie ve y el único que no avisa cuando se salta. Está explicado completo aquí abajo.

3

Suelta el remote heredado, pon el tuyo y empuja

En ese orden, y solo después el commit y el push. El prompt del final lo hace de punta a punta y comprueba el resultado antes de decirte que terminó.

El segundo paso: el .gitignore del kit deja fuera justo lo que hay que subir

El kit es un repositorio público de plantilla y su .gitignore está escrito para mantenerlo limpio: excluye agent/, config/, tests/, requirements.txt, Dockerfile y docker-compose.yml. Allá tiene sentido, porque esos archivos no están en GitHub a propósito: los escribe Claude Code en tu máquina durante la entrevista.

En tu repositorio pasa exactamente al revés: eso es lo que el servidor necesita para construir tu agente. Si empujas sin tocarlo, subes un repositorio sin agente y el servidor construye la nada. El error que te sale después habla del build, no del .gitignore, y ahí se va la tarde.

tiene que entrar

Lo que hoy está ignorado y debe dejar de estarlo

  • agent/ — tu agente entero.
  • config/ — el prompt del sistema y los datos de tu negocio.
  • tests/ — las pruebas locales.
  • requirements.txt — la lista de dependencias que el servidor instala.
  • Dockerfile — la receta con la que el servidor construye la imagen.
  • docker-compose.yml.

sigue fuera

Lo que no sube ni después del cambio

  • .env — ahí viven la llave de Anthropic y la de tu proveedor.
  • *.db, *.sqlite y *.sqlite3 — la base de datos local.
  • __pycache__/ y *.py[cod].
  • .venv/ y venv/.
  • knowledge/* — tus archivos del negocio, salvo knowledge/.gitkeep.
  • config/session.yaml — el estado de la entrevista.
  • .DS_Store, Thumbs.db, .vscode/ y .idea/.

Los tres comandos que te tocan a ti

El primero suelta el repositorio ajeno, el segundo apunta al tuyo y el tercero comprueba que los archivos del agente van a subir de verdad. En el segundo cambias TU-USUARIO y el nombre del repositorio por los tuyos.

Soltar el repo ajeno

git remote remove origin

Apuntar al tuyo

git remote add origin https://github.com/TU-USUARIO/mi-agente.git

Comprobar que los archivos del agente sí van a subir

git ls-files | grep -E "agent/main.py|Dockerfile"

la secuencia completa, de arriba a abajo

git remote remove origin
git remote add origin https://github.com/TU-USUARIO/mi-agente.git
git add .
git commit -m "feat: mi agente de WhatsApp"
git branch -M main
git push -u origin main

Esa secuencia está aquí para que reconozcas lo que pasa en pantalla, no para que la escribas: el prompt del final la corre por ti y se detiene si algo no cuadra.

Cómo compruebas que quedó bien sin entender git

git ls-files lista los archivos que el repositorio va a subir. No hace falta leerla entera: son tres cosas.

  • Aparece agent/main.py. Si no está, el .gitignore sigue siendo el del kit y el paso 2 quedó pendiente.
  • Aparece Dockerfile. Es la receta con la que el servidor construye tu agente; sin él no hay nada que desplegar.
  • No aparece .env. Ahí están tus llaves, y un repositorio en GitHub las deja a la vista de quien pase.

Si .env alcanzó a subir, borrarlo del repositorio no alcanza: quedó en el historial. Genera una llave nueva de Anthropic y otra de tu proveedor, jubila las viejas y cámbialas en tu .env.

otra opción, y esta no tiene vuelta atrás

Si prefieres no arrastrar el historial de AgentKit

Hay un camino más corto: borrar la carpeta de git del clon y empezar uno nuevo, con rm -rf .git && git init, antes que todo lo demás. Después ya no hay remote heredado que soltar y el primer comando de arriba sobra.

Lo que cuesta: borras el historial completo del kit y eso no se deshace. No hay papelera ni deshacer. Si no tienes clarísimo que no lo quieres, quédate con la secuencia de arriba, que llega al mismo lugar sin romper nada.

Prompt 05 · Sube tu agente a tu repositorio, de punta a punta

Reemplaza el .gitignore, suelta el remote heredado, empuja y comprueba que .env no subió.

Quiero subir mi agente a MI repositorio de GitHub. Hazlo tú de punta a punta.

CONTEXTO, y esto es lo importante:
- Estoy parado DENTRO del clon del repo público de AgentKit. Ya hay un repositorio de git aquí y su remote "origin" apunta al repo de otra persona. Por eso `git init` no aplica y `git remote add origin` va a fallar con "remote origin already exists".
- El .gitignore de este clon excluye a propósito agent/, config/, tests/, requirements.txt, Dockerfile y docker-compose.yml. Eso es exactamente lo que yo sí necesito subir: si no lo cambias, mi repo queda vacío y el despliegue construye la nada.
- Mi repositorio vacío, ya creado en GitHub sin README y sin .gitignore: [PEGA AQUÍ la URL, por ejemplo https://github.com/mi-usuario/mi-agente.git]

OBJETIVO:
Que mi repositorio tenga el agente completo y NO tenga ningún secreto.

QUÉ HACER, EN ESTE ORDEN:
1. Reemplaza el .gitignore por uno de producción que siga ignorando .env, *.db, __pycache__/, .venv/, knowledge/* salvo knowledge/.gitkeep y config/session.yaml — y que YA NO ignore agent/, config/, tests/, requirements.txt, Dockerfile ni docker-compose.yml.
2. Suelta el remote heredado con `git remote remove origin`.
3. Agrega el mío con `git remote add origin` y la URL que te di.
4. `git add .`, commit "feat: mi agente de WhatsApp", `git branch -M main`, `git push -u origin main`.
5. Si el push falla por autenticación, dime en español qué me pide GitHub. No inventes credenciales ni tokens.

RESTRICCIONES DURAS:
- NUNCA ejecutes `git init` en esta carpeta.
- NUNCA hagas `rm -rf .git` sin pedirme permiso y explicarme que eso borra el historial sin vuelta atrás.
- El archivo .env NO puede entrar al commit bajo ninguna circunstancia.
- NO subas nada de knowledge/ salvo el .gitkeep: son datos de mi negocio.
- NO empujes a un repositorio que no sea el que te di.

CRITERIO DE ACEPTACIÓN, compruébalo tú antes de decirme que terminaste:
- `git remote -v` muestra SOLO mi URL.
- `git ls-files | grep -E "^agent/main\.py$"` devuelve una línea.
- `git ls-files | grep -E "^Dockerfile$"` devuelve una línea.
- `git ls-files | grep -c "^\.env$"` devuelve 0.
Si alguno falla, arréglalo y vuelve a comprobar. No me reportes éxito con un criterio en rojo.

QUÉ REPORTAR AL FINAL:
La URL de mi repositorio, cuántos archivos subieron, la confirmación explícita de que .env NO está en el repositorio, y el resultado de cada criterio de arriba en una línea cada uno.

11 · Railway

De tu GitHub a internet, con los nombres de cada botón

Railway toma tu repositorio, construye la imagen a partir del Dockerfile en sus servidores y deja tu agente corriendo en una dirección pública. Docker no hace falta en tu computadora: lo único que tiene que estar bien es lo que subiste.

Son seis pasos y el orden importa en uno solo: la base de datos va antes que las variables, porque una de las variables es una referencia a la base y no puedes referenciar algo que todavía no existe.

Los seis pasos, en orden

1

Crear el proyecto

Entra a railway.app y crea tu cuenta si todavía no la tienes: ahí mismo se abre el dashboard, que es la pantalla donde vive todo lo de esta sección.

Dentro: New Project, después GitHub repo. Busca el repositorio de tu agente y dale Deploy Now.

Si tu cuenta todavía no tiene GitHub enlazado, Railway te lo pide ahí mismo.

2

La base de datos, primero

Clic derecho en el canvas del proyecto, o el botón Create, y de ahí Database y Add PostgreSQL. Queda como un servicio aparte, al lado del tuyo.

El CLAUDE.md del kit llama New a ese mismo menú: es el mismo camino con otra etiqueta.

3

Las variables, en tu servicio

Haz clic en TU servicio —el del agente, no el de la base— y entra a Variables. Las seis de abajo van ahí.

Si las cargas en el servicio de PostgreSQL, tu agente no las ve y arranca como si no existieran.

4

Nada de PORT

Es el único de los seis que consiste en no hacer algo: no agregues una variable PORT. Railway la pone él.

5

El dominio

Tu servicio, Settings, Networking, Public Networking y ahí Generate Domain. Te queda una dirección del tipo tu-app.up.railway.app.

Si antes creaste un TCP Proxy, el botón no aparece hasta que lo borres.

6

Verificar

Abre tu dirección en el navegador o corre el comando de aquí abajo. Tiene que contestar ok.

Las seis variables del despliegue

Estas son las que necesita tu agente para funcionar allá arriba. Las de tu .env local no viajan solas: el archivo .env se queda en tu computadora a propósito, y aquí se escriben a mano una por una.

ANTHROPIC_API_KEY

La misma llave de Anthropic que tienes en tu .env local, la que empieza con sk-ant-. No es una nueva.

ANTHROPIC_MODELOpcional, con matiz
claude-sonnet-5

Si no la pones, tu agente usa claude-sonnet-5. Las otras dos opciones son claude-opus-5 y claude-haiku-4-5, y lo que cambia entre ellas es lo que te cuesta cada conversación.

WHATSAPP_PROVIDER

Exactamente una de estas dos palabras, en minúsculas: zernio o meta. La que elegiste al principio. Si falta o va mal escrita, el chequeo de salud contesta error y tu agente no atiende a nadie.

ENVIRONMENTOpcional, con matiz
production

Fuera de Railway el valor por omisión es development. Aquí va production, escrito así, en minúsculas.

DATABASE_URL
${{Postgres.DATABASE_URL}}

Se escribe tal cual, con las dos llaves de cada lado: es una referencia al servicio de PostgreSQL, no una dirección. Si tu servicio de base quedó con otro nombre, ese nombre va en lugar de Postgres.

ZERNIO_* o META_*

Las del proveedor que elegiste, iguales a las de tu .env: con Zernio, ZERNIO_API_KEY y ZERNIO_WEBHOOK_SECRET; con Meta, META_ACCESS_TOKEN, META_PHONE_NUMBER_ID, META_VERIFY_TOKEN y META_APP_SECRET. El secreto del webhook y el verify token los inventaste tú: aquí va el mismo valor exacto, no uno nuevo.

Las tres que muerden

Si te saltas la base

Arranca igual, y se olvida de todos cada vez que despliegas

Sin DATABASE_URL tu agente no falla: cae a SQLite dentro del contenedor. Y ese disco es efímero. Cada redespliegue —cada push, cada cambio de variable— borra el historial de todas las conversaciones, y tus clientes vuelven a empezar de cero contigo.

La otra mitad: Railway no copia sola la URL de la base. Hay que escribir la referencia con las llaves dobles, ${{Postgres.DATABASE_URL}}, y si tu servicio de base quedó con otro nombre, ese nombre va en lugar de Postgres.

Lo que Railway no hace solo

Dos cosas que parecen automáticas y no lo son

El dominio no se genera solo. Railway despliega y no te da dirección hasta que se la pides: tu servicio, Settings, Networking, Public Networking, Generate Domain.

Agregar o cambiar una variable tampoco la aplica. Queda como staged changes, en espera, hasta que revisas el cambio y despliegas. Si cambiaste una variable y tu agente sigue comportándose igual que antes, casi siempre es esto.

No agregues PORT

La variable que rompe el despliegue por estar de más

Railway inyecta PORT cuando arranca el contenedor, y el Dockerfile lo respeta a propósito: el CMD va en forma shell para que ${PORT:-8000} se expanda en ese momento y no antes.

Si la fijas tú en 8000, el contenedor arranca, se ve verde en el dashboard y nunca recibe tráfico.

Comprobar que tu agente está vivo en internet

curl https://tu-app.up.railway.app/

Cambia tu-app por el dominio que te dio Railway. Si en vez de ok te contesta degradado o error, no lo adivines: el diagnóstico se lee igual que en local, y ahí está qué significa cada estado y en qué campo viene el detalle.

Prompt 06 · De tu repositorio a Railway

Claude Code revisa el repositorio antes de que abras Railway y después te dicta los clics con el nombre literal de cada botón.

Voy a subir mi agente a Railway. Prepara tú el repositorio y después díctame los clics con el nombre de cada botón.

CONTEXTO:
- Mi agente ya está en MI repositorio de GitHub y corre en local.
- Railway construye la imagen en sus servidores. No tengo Docker instalado.
- Railway inyecta la variable PORT.
- Mi repositorio: [PEGA AQUÍ la URL de tu repositorio]

OBJETIVO:
Que mi agente corra en una dirección pública de Railway, con PostgreSQL conectado y el chequeo de salud contestando "ok".

QUÉ HACER, EN ESTE ORDEN:
1. Antes de que yo abra Railway, revisa mi repositorio:
- que el CMD del Dockerfile use ${PORT:-8000} en forma shell y no un 8000 fijo;
- que requirements.txt diga sqlalchemy[asyncio]>=2.0.52 y traiga asyncpg>=0.31.0;
- que .env NO esté subido: `git ls-files | grep -c "^\.env$"`.
2. Si corregiste algo, haz commit y push a main.
3. Dicta los clics, uno por línea, con el nombre literal del botón: crear el proyecto, agregar PostgreSQL ANTES que las variables, cargarlas en MI servicio, generar el dominio y verificar.
4. Dame la lista de variables, una por línea, con su valor. Los pego yo en Railway.
5. Cuando te avise que terminé, corre tú el curl a mi dirección y dime qué contestó.

RESTRICCIONES DURAS:
- NO agregues ni me hagas agregar una variable PORT.
- NO escribas la cadena de conexión de PostgreSQL a mano: en DATABASE_URL va la referencia ${{Postgres.DATABASE_URL}}, tal cual.
- NO me dejes saltarme PostgreSQL "por ahora".
- NO copies valores de mi .env dentro de ningún archivo del repo.
- NO me pidas que instale Docker.

CRITERIO DE ACEPTACIÓN, compruébalo tú:
- `curl https://<mi-dominio>/` devuelve "status":"ok".
- En la lista de variables que me diste no aparece PORT.
- DATABASE_URL es la referencia con llaves dobles, no una cadena postgresql:// a mano.

QUÉ REPORTAR AL FINAL:
Qué tocaste en el repositorio y por qué, la lista de variables como quedó, mi dirección pública y el curl en una línea.

Hasta aquí llegan los clics de este proyecto. Ponerle tu propio dominio, tener un entorno de pruebas aparte del que ven tus clientes, cambiar variables por entorno, deshacer un despliegue que salió mal o dejar que cada push se publique solo es otro tema y tiene su guía: All Deploy. Ahí está eso, y lo mismo cuando el destino no es Railway.

12 · el webhook

El webhook: decirle a WhatsApp a dónde avisar

Un webhook es la dirección a la que tu proveedor toca el timbre cuando entra un mensaje. Nada más que eso. Tu agente ya está en internet y ya sabe contestar, pero todavía no hay nadie que le avise: el mensaje llega al proveedor y ahí se queda.

Por eso este paso va al final y no antes: hace falta la URL pública, la que quedó cuando generaste el dominio. La que se pega en el panel es esa misma con /webhook al final, y ese pedacito es de los que se olvidan: sin él el aviso llega a la raíz, que solo sabe decir si tu agente está vivo.

Con Zernio, clic por clic

Cinco clics en el panel donde ya sacaste la llave. Ten a mano la URL de tu servicio y el secreto que inventaste.

1

Webhooks → Create webhook

En el panel de Zernio, la sección Webhooks, y ahí el botón Create webhook.

2

La URL, con /webhook al final

Pega la URL pública de tu servicio y agrégale /webhook. Queda del estilo https://tu-app.up.railway.app/webhook.

3

Secret: el mismo texto, carácter por carácter

En la casilla Secret va exactamente el valor que cargaste en ZERNIO_WEBHOOK_SECRET. Si no coinciden, la firma no cuadra y tu servidor rechaza cada aviso con un 401.

4

Marca el evento message.received

Es el único que necesitas: es el aviso de que entró un mensaje.

5

Guardar, y después Send test

Guarda el webhook y usa el botón Send test. Si tu servidor contesta 200, el circuito está armado.

Estos nombres de pantalla salen de la documentación del propio kit. Si en tu panel alguna etiqueta se llama distinto, el orden es el mismo: crear el webhook, pegar la URL, poner el secreto, marcar el evento.

Con Meta, clic por clic

El mismo trámite en la consola de desarrolladores, con un nombre distinto para cada cosa.

1

WhatsApp → Configuration

En developers.facebook.com, dentro de tu app: el producto WhatsApp, y ahí Configuration.

2

Callback URL

La URL pública de tu servicio con /webhook al final, igual que en el caso de arriba.

3

Verify Token: el mismo texto exacto

El valor que pusiste en META_VERIFY_TOKEN. Meta se lo manda una sola vez a tu servidor para comprobar que esa URL es tuya.

4

Suscríbete al campo messages

En la lista de campos del webhook, marca messages. Es el que trae lo que escriben tus clientes.

5

Guardar

Guarda y espera a que Meta marque la URL como verificada.

Si el verify token no coincide, tu servidor responde 403 a propósito. Contestarle 200 le haría creer a Meta que la URL quedó verificada sin estarlo, y después no llegaría ni un mensaje.

Qué hace tu agente con cada aviso, y por qué

El aviso no se atiende de frente. Pasa por dos filtros antes de que nadie lea el mensaje, y la respuesta al proveedor sale antes que la respuesta al cliente. Cada una de las tres decisiones tapa una falla distinta.

por qué revisa antes de leer

Primero la firma, después el mensaje

Cada aviso viene firmado. Tu agente calcula la firma que debería tener y, si no cuadra, tira el aviso sin leerlo: así nadie que conozca tu URL puede inventarle mensajes.

Esa revisión solo ocurre si cargaste el secreto. Lo de abajo es exactamente eso.

el aviso que llega dos veces

Ignora los repetidos

Cada mensaje trae su identificador. Si el mismo llega dos veces, se responde una sola vez.

Llega dos veces más seguido de lo que parece: la entrega del proveedor es de las que prefieren repetir un aviso antes que perderlo.

por qué contesta antes de pensar

Contesta «recibido» de inmediato y piensa después

Lo primero que hace tu agente al recibir un aviso es decirle al proveedor que lo recibió. Recién después busca el historial, le pregunta a Claude y manda la respuesta por WhatsApp.

No es capricho: el proveedor espera un 2xx en unos cinco segundos, y pensar tarda más que eso. Si no lo recibe, reintenta el mismo mensaje hasta siete veces.

Y siete reintentos no son siete avisos perdidos en el aire: son siete respuestas. Tu cliente vería siete veces lo mismo.

el que se deja vacío y no avisa

Sin secreto, la puerta queda abierta

Si ZERNIO_WEBHOOK_SECRET queda vacío —o META_APP_SECRET, si fuiste por Meta—, la verificación de firma devuelve verdadero y deja pasar todo lo que llegue a tu URL.

Lo que lo hace traicionero: tu agente arranca igual, el chequeo de salud no mira esto, y lo único que avisa es una línea en los registros. Viene vacío de fábrica para que puedas probar sin trabarte.

Cárgalo antes de atender clientes de verdad, y pon el mismo valor en el alta del webhook. Mientras esté vacío, cualquiera que sepa tu URL puede inyectarle mensajes a tu agente.

Cómo se ve cuando ya quedó

Que el alta se haya guardado no prueba nada. Esto sí: le escribes al número de tu agente desde tu propio celular y las tres cosas pasan una detrás de otra.

el circuito cerrado

tú, desde tu celular
  →  Hola, ¿a qué hora abren?

el registro del servidor
  →  POST /webhook 200 · mensaje recibido

tu agente, en WhatsApp
  →  Abrimos de lunes a sábado, de 9 a 19.

Prompt 07 · Dar de alta el webhook y comprobarlo de verdad

Empieza mirando el chequeo de salud y se para ahí si tu agente todavía no puede responder. No te dice que terminó hasta que la respuesta llegue a tu celular.

Da de alta el webhook de mi agente y no me digas que terminaste hasta que me llegue una respuesta al celular.

CONTEXTO:
- Mi agente ya está desplegado. Su URL pública es: [PEGA AQUÍ la URL, por ejemplo https://mi-app.up.railway.app]
- Mi proveedor es [ESCRIBE AQUÍ: zernio o meta].
- El secreto del webhook ya está cargado en las variables de mi servicio: ZERNIO_WEBHOOK_SECRET con Zernio, META_VERIFY_TOKEN y META_APP_SECRET con Meta.

OBJETIVO:
Que yo escriba desde mi celular y me conteste mi agente.

QUÉ HACER, EN ESTE ORDEN:
1. Primero `curl <mi URL>/` y dime qué dice "status". Si dice "degradado" o "error", PÁRATE AHÍ y dime qué variable corregir: dar de alta un webhook contra un agente que no puede responder no sirve de nada.
2. Si dice "ok", dicta los clics de mi panel uno por línea, con la URL exacta que tengo que pegar: la mía con /webhook al final.
3. Recuérdame que el secreto del panel tiene que ser el mismo texto exacto que la variable del servidor.
4. Con Zernio: evento message.received, guardar, botón Send test, y dime qué código tiene que contestar mi servidor. Con Meta: suscribirme al campo messages y guardar.
5. Pídeme que le escriba al número desde mi celular y espera a que yo te diga qué pasó.

RESTRICCIONES DURAS:
- NO me digas que deje el secreto vacío "para probar".
- NO des de alta el webhook contra localhost ni contra una URL de prueba.
- NO me digas que quedó listo porque el alta se guardó. Solo cuenta si llegó la respuesta a mi celular.

CRITERIO DE ACEPTACIÓN, compruébalo tú:
- `curl <mi URL>/` devuelve "status":"ok".
- Yo te confirmo que escribí desde el celular y llegó la respuesta.

QUÉ REPORTAR AL FINAL:
La URL que quedó dada de alta, el evento o campo al que me suscribí, y si llegó la respuesta al celular.

hasta aquí el montaje

Ya está: tu número contesta solo

Cuando esa respuesta llega a tu celular, terminaste de construir. Tu agente vive en internet, atiende su propio número y guarda el historial de cada conversación en la base que le agregaste en Railway.

Queda una sola condición antes de apuntarle clientes de verdad, y es la de aquí arriba: que el secreto del webhook no se haya quedado vacío.

Las cuatro secciones que siguen ya no construyen nada. Son qué mirar cuando algo falla, cómo cambiarle el tono o los precios, cuánto te va a costar al mes y las dudas que suelen quedar.

Y una cosa que se resuelve sola: tu agente siempre le contesta a quien le escribió, así que nunca sale de la ventana de 24 horas que impone WhatsApp — de qué va esa ventana, en la sección donde eliges proveedor.

13 · cuando algo falla

Cuando algo falla: síntoma, causa, arreglo

Esta sección es una tabla de búsqueda, no una lectura. Cuando algo deja de funcionar, el orden que ahorra horas es siempre el mismo: primero le preguntas a tu agente cómo está, y solo después buscas tu síntoma en las fichas de abajo.

Ninguna de estas dieciocho fallas llega con un aviso claro. Casi todas se ven como silencio: el número no contesta, la respuesta no sale, el historial desapareció. Por eso cada ficha empieza por lo que ves en pantalla, no por la causa.

empieza siempre por aquí

Antes de tocar nada, pregunta el chequeo de salud

Un curl a la raíz de tu URL y lees el status: si dice error, el motivo está en detalle; si dice degradado, está en conexion.detalle. Esa sola línea te dice cuál de las fichas de abajo te toca, y te evita cambiar cosas al azar.

Los tres estados, y por qué los tres contestan 200, están en probarlo en tu compu.

El diagnóstico de un solo comando

curl https://tu-app.up.railway.app/

Las dieciocho fallas de este kit

Busca por la primera línea de cada ficha: es exactamente lo que estás viendo. La causa y el arreglo vienen debajo, en ese orden.

01 · git

El remote heredado

el síntoma
git remote add origin responde: error: remote origin already exists.
la causa
Estás dentro del clon del kit y su origin apunta al repo ajeno.
el arreglo
git remote remove origin y después git remote add origin con el tuyo. Nunca git init aquí.

02 · git

El repo subió casi vacío

el síntoma
Subiste a GitHub y el repo se ve casi vacío; Railway construye y falla.
la causa
El .gitignore del kit excluye agent/, config/, tests/, requirements.txt, Dockerfile y docker-compose.yml.
el arreglo
Reemplaza el .gitignore antes del push. Comprueba con git ls-files: tienen que aparecer agent/main.py y Dockerfile.

03 · salud

Dice degradado

el síntoma
El chequeo de salud dice status degradado.
la causa
El servidor arrancó pero el chequeo de conexión con el proveedor falló: va a recibir mensajes y no va a poder contestarlos.
el arreglo
Lee conexion.detalle, que nombra la variable que falta o la credencial rechazada, y corrígela en Variables.

04 · salud

Dice error

el síntoma
El chequeo de salud dice status error.
la causa
Ni siquiera se pudo armar el proveedor: WHATSAPP_PROVIDER falta, está vacía o mal escrita.
el arreglo
Lee detalle en la raíz y pon WHATSAPP_PROVIDER=zernio o =meta, exactamente en minúsculas.

05 · webhook

Dice ok y aun así nadie recibe respuesta

el síntoma
El chequeo de salud dice ok pero nadie recibe respuesta.
la causa
El webhook no está dado de alta, apunta a otra URL, le falta el /webhook al final, o no marcaste message.received.
el arreglo
Vuelve a la sección 12. En Zernio usa Send test: si tu servidor responde 200, el circuito está.

06 · envío

El mensaje entra y la respuesta no sale

el síntoma
Llega el mensaje, el registro lo muestra, y la respuesta nunca sale.
la causa
La llave del proveedor es inválida o la URL de la API quedó apuntando a un lugar inexistente.
el arreglo
Si tienes ZERNIO_BASE_URL declarada y vacía en tu .env, bórrala o coméntala: una URL vacía no tiene esquema https:// y el envío falla antes de salir a la red.

07 · duplicados

Tus clientes reciben lo mismo varias veces

el síntoma
Tus clientes reciben la misma respuesta varias veces.
la causa
El webhook no está contestando 2xx en 5 segundos y el proveedor reintenta hasta 7 veces.
el arreglo
Pídele a Claude Code que verifique que no haya trabajo pesado antes de devolver la respuesta. La respuesta va primero, el trabajo después.

08 · firma

Cualquiera le puede inyectar mensajes

el síntoma
Cualquiera que sepa tu URL le puede inyectar mensajes a tu agente.
la causa
ZERNIO_WEBHOOK_SECRET (o META_APP_SECRET) está vacío: la verificación de firma devuelve verdadero y solo avisa en los registros.
el arreglo
Carga el secreto del webhook en Variables y pon el mismo valor en el alta del webhook. Redespliega.

09 · memoria

Se olvida de todos sus clientes

el síntoma
Tu agente se olvida de todos sus clientes cada vez que despliegas.
la causa
No cargaste DATABASE_URL en Railway: cayó a SQLite dentro del contenedor, y ese disco es efímero.
el arreglo
Agrega PostgreSQL y escribe DATABASE_URL = ${{Postgres.DATABASE_URL}} en las Variables de tu servicio.

10 · Railway

Desplegó y la URL no responde

el síntoma
Railway dice que desplegó pero la URL no responde nada.
la causa
El servicio no tiene dominio público: Railway no lo pone solo.
el arreglo
Tu servicio, Settings, Networking, Public Networking, Generate Domain.

11 · Railway

Cambiaste una variable y no pasó nada

el síntoma
Cambiaste una variable en Railway y no pasó nada.
la causa
Los cambios de variables quedan como staged changes hasta que los revisas y despliegas.
el arreglo
Aplica el cambio desde el dashboard y espera el redespliegue.

12 · Railway

Arranca y nunca le llega tráfico

el síntoma
El contenedor arranca en Railway pero nunca le llega tráfico.
la causa
Fijaste PORT a mano.
el arreglo
Borra la variable PORT. El Dockerfile usa ${PORT:-8000} en forma shell justamente para esto.

13 · arranque

Muere al arrancar con greenlet_spawn

el síntoma
Tu agente muere al arrancar con un error de greenlet_spawn.
la causa
Falta el extra [asyncio] de SQLAlchemy.
el arreglo
En requirements.txt tiene que decir sqlalchemy[asyncio]>=2.0.52, no sqlalchemy a secas.

14 · arranque

Agregaste PostgreSQL y ya no arranca

el síntoma
Agregaste PostgreSQL y tu agente no arranca.
la causa
Falta asyncpg: la memoria reescribe la URL a postgresql+asyncpg://.
el arreglo
asyncpg>=0.31.0 en requirements.txt, aunque en local uses SQLite.

15 · Meta

Verificó la URL y después nada

el síntoma
Meta dice que verificó la URL y después no llega nada.
la causa
El verify token no coincidía y el servidor devolvió 403 a propósito.
el arreglo
Que META_VERIFY_TOKEN sea el mismo texto exacto en Variables y en la casilla de Meta. Reintenta la verificación.

16 · respuestas

Se cortan a la mitad

el síntoma
Las respuestas se cortan a la mitad.
la causa
ANTHROPIC_MAX_TOKENS demasiado bajo: el razonamiento interno del modelo también cuenta contra ese tope.
el arreglo
Súbelo o déjalo en el default de 4096.

17 · instalación

start.sh se corta en el paso 2

el síntoma
bash start.sh se corta en el paso 2.
la causa
Claude Code no está instalado o no quedó en el PATH.
el arreglo
npm install -g @anthropic-ai/claude-code, corre claude una vez para autenticarte, y vuelve a bash start.sh.

18 · contenido

Inventa un precio

el síntoma
Tu agente inventa un precio.
la causa
Ese dato no está en config/prompts.yaml ni en knowledge/.
el arreglo
Pon el precio en un .txt dentro de knowledge/ y pídele a Claude Code que regenere el prompt. Si tu agente ya está en línea, que además haga el push: hasta entonces el cambio vive solo en tu computadora.

La segunda herramienta: los registros

En desarrollo tu agente escribe su propio detalle en los registros y deja fuera el ruido de las librerías, a propósito: ahí se lee lo que hizo tu agente con tu mensaje, no lo que hizo Python por debajo.

Prompt 08 · Diagnostica en orden, sin que yo lea registros

Pégaselo a Claude Code con tu URL y tu síntoma. Va del estado a la causa sin saltarse pasos, y termina dejándote una sola cosa por hacer.

Mi agente de WhatsApp no hace lo que debería. Diagnostícalo tú, en orden, sin que yo lea registros.

CONTEXTO:
- Mi agente está desplegado y su URL pública es [PEGA AQUÍ https://tu-app.up.railway.app]
- Mi proveedor es [ESCRIBE AQUÍ: zernio o meta].
- Lo que yo veo es [ESCRIBE AQUÍ el síntoma, con tus palabras].
- No programo. Resuélvelo tú y explícame en español.

OBJETIVO:
Encontrar la causa, arreglarla y dejarme una sola cosa por hacer.

QUÉ HACER, EN ESTE ORDEN:
1. curl a la raíz y clasifica el status. "error": la causa es WHATSAPP_PROVIDER, en detalle, para ahí. "degradado": está en conexion.detalle, para ahí. "ok": sigue bajando.
2. No llega nada: revisa el alta del webhook, la URL terminada en /webhook y el evento message.received marcado.
3. Llega y no sale respuesta: credenciales de envío del proveedor y si ZERNIO_BASE_URL quedó declarada y vacía.
4. Contesta varias veces: que devuelva 2xx antes de trabajar y descarte por id los avisos repetidos.
5. Se olvida de conversaciones viejas: DATABASE_URL.
6. Inventa precios: config/prompts.yaml y knowledge/.
7. Cambié una variable en Railway y no pasó nada: staged changes.

RESTRICCIONES DURAS:
- NO me digas "responde 200, está todo bien": responde 200 aun degradado, a propósito.
- NO cambies el modelo ni el prompt a ver si así funciona.
- NO borres la base de datos ni el archivo .env.
- NO me digas que los duplicados se quitan borrando webhooks: el aviso repetido ya se descarta por su id. Lo que sí los provoca es no contestar 2xx en cinco segundos.
- NO me reportes una causa sin comprobar los pasos anteriores.

CRITERIO DE ACEPTACIÓN, compruébalo tú:
- curl a la raíz devuelve "status":"ok".
- Le escribo al número y llega una sola respuesta.

QUÉ REPORTAR AL FINAL:
Tres cosas y nada más: cuál era la causa, qué cambiaste tú, y qué tengo que hacer yo.

Si tu síntoma es de Railway y lo que te falta es el camino del menú, los clics están en la sección 11; si es el alta del webhook, en la 12. Y si lo que cambiaste fue un archivo y no una variable, el push que lo pone en línea está en personalizarlo después. Aquí van los síntomas, no el paso a paso.

14 · personalizarlo

Personalizarlo después, y el límite que nadie te dice

Tu agente no queda congelado el día que lo pones en línea. Cambiarle el tono, enseñarle un precio nuevo o contarle de un servicio que acabas de abrir es cuestión de minutos, y no se toca código: se tocan dos archivos de texto.

Lo que sí cuesta trabajo es otra cosa, y conviene saberla antes de prometérsela a un cliente.

Lo fácil, que de verdad es fácil

Abres la carpeta de tu agente en la terminal, arrancas Claude Code y se lo pides en español, con tus palabras. Estas tres cosas entran por ahí:

  • El tono: que salude más corto, que hable de tú, que deje de usar signos de admiración.
  • Información nueva: un precio que subió, el horario de los sábados, un servicio que acabas de abrir.
  • Lo que no debe decir: que no prometa tiempos de entrega, que no negocie descuentos, que no opine de la competencia.

Todo eso vive en config/prompts.yaml, que es la personalidad, y en config/business.yaml, que son los datos de tu negocio. Son dos archivos de texto: pídele a Claude Code que los edite y que te diga en español qué cambió.

el paso que se olvida

Lo que cambias en tu computadora no llega solo a tu número

Editar esos archivos cambia el agente de tu computadora, no el que está atendiendo. El que atiende corre en Railway, y Railway construye desde tu repositorio de GitHub: mientras el cambio no llegue ahí, tu cliente sigue recibiendo el precio viejo, y nada falla ni te avisa.

Así que pídele a Claude Code, en la misma sentada, que haga el commit y el push a main. Ese push es el que dispara el redespliegue, y cuando termina, tu número ya contesta con lo nuevo.

Los archivos de knowledge/ son la excepción: siguen sin salir de tu máquina. Lo que viaja es el prompt del sistema ya armado, en config/prompts.yaml. Por eso, cuando metas un precio nuevo ahí, el pedido va completo: guárdalo, regenera el prompt, y haz el push.

el límite real

agent/tools.py se escribe, y hoy nadie lo llama

Durante la entrevista, Claude Code genera agent/tools.py con tres funciones listas para usarse y con un bloque de funciones sugeridas según para qué dijiste que querías el agente:

  • Listas: cargar_info_negocio(), obtener_horario() y buscar_en_knowledge().
  • Si dijiste agendar citas: obtener_slots_disponibles, reservar_cita, cancelar_cita.
  • Si dijiste pedidos: agregar_al_carrito, ver_carrito, confirmar_pedido.
  • Si dijiste leads o ventas: registrar_lead, calificar_lead, escalar_a_vendedor.
  • Si dijiste soporte: crear_ticket, consultar_ticket, escalar_ticket.

Pero ningún módulo importa ese archivo y nadie le pasa tools= a la API. O sea: las funciones están escritas y nunca se ejecutan.

Conectarlas al ciclo de uso de herramientas es un trabajo aparte. No es imposible ni es larguísimo, pero no sale de la entrevista: sale del primer prompt de aquí abajo.

Entonces por qué sí se sabe tu menú

Porque la información de tu negocio no le llega por herramientas: le llega por el prompt del sistema, que se arma con config/prompts.yaml, config/business.yaml y lo que dejaste en knowledge/. El agente lo lee completo en cada turno, y por eso contesta precios, horarios y condiciones sin ejecutar nada.

La frontera es esa: para contestar no hace falta nada de tools.py; hace falta para hacer. Conversar, entender y dejar los datos en el historial ya lo hace hoy. Agendar, cobrar o apartar stock no, hasta que alguien lo cablee.

Qué cuesta cada cambio

La misma pregunta contestada por columnas: dónde se toca, y cuánto trabajo es de verdad.

Cambiar el tono

Dónde se toca
config/prompts.yaml
Cuánto cuesta en trabajo
Minutos. Se lo pides a Claude Code en español, lo reescribe él, y el push lo pone en línea.

Agregar información: un precio, un horario, un servicio

Dónde se toca
config/business.yaml y un .txt en knowledge/
Cuánto cuesta en trabajo
Minutos. Lo que pongas en knowledge/ entra literal al prompt, sin resumir, y viaja con el push.

Que ejecute una acción de verdad: agendar, cobrar, apartar stock

Dónde se toca
agent/tools.py y el ciclo de uso de herramientas, dentro de agent/
Cuánto cuesta en trabajo
Un trabajo aparte, con su prueba. Es el primer prompt de aquí abajo.

Cambiar de proveedor

Dónde se toca
El adaptador del proveedor, WHATSAPP_PROVIDER y el alta del webhook
Cuánto cuesta en trabajo
Una sentada. El adaptador lo genera Claude Code; los clics del panel los das tú.

Un segundo agente para otro negocio

Dónde se toca
Otra carpeta, otra entrevista, otro número
Cuánto cuesta en trabajo
Se monta aparte y no toca al que ya está corriendo.

El tope de la respuesta también cuenta lo que el modelo piensa

ANTHROPIC_MAX_TOKENS viene comentada en el .env y su valor por default es 4096. Es el techo de lo que el agente puede escribir de una sola vez.

En los modelos actuales, el razonamiento interno cuenta contra ese mismo tope. No es solo lo que ve el cliente.

Por eso, si lo dejas con el margen justo, una pregunta que exija pensar deja al agente sin espacio para contestar y la respuesta sale cortada a la mitad. Si lo vas a mover, muévelo con holgura: 4096 aguanta bien una conversación de WhatsApp.

Los tres prompts para pegar

Prompt 09 · Cablear una herramienta de verdad

Conecta una función de agent/tools.py al ciclo de uso de herramientas, con una prueba que falla si la función no se llama.

Quiero que una función de agent/tools.py se ejecute de verdad. Hazlo tú de punta a punta.

CONTEXTO:
- Mi agente ya corre y contesta por WhatsApp.
- agent/tools.py existe, con sus funciones ya escritas. Que yo sepa, ningún módulo lo importa y ninguna llamada a la API lleva tools=, así que hoy no se ejecuta ninguna.
- La acción que quiero que ejecute:
[ESCRIBE AQUÍ: por ejemplo, reservar una cita]
- El sistema donde tiene que quedar registrada:
[ESCRIBE AQUÍ: por ejemplo, mi calendario de Google]

OBJETIVO:
Que esa acción quede hecha en el otro sistema cuando un cliente la pide por WhatsApp, y que el agente solo la confirme si quedó hecha.

QUÉ HACER, EN ESTE ORDEN:
1. Revisa agent/ y confírmame, con archivo y línea, que hoy nadie importa tools.py y que ninguna llamada lleva tools=. Si ya estaba cableado, dímelo y no toques nada.
2. Escribe la función en agent/tools.py y atrapa sus errores.
3. Decláramela como herramienta, con su esquema de entrada.
4. Implementa el ciclo completo: manda las herramientas en la llamada, ejecuta la que el modelo pida, devuélvele el resultado y deja que redacte la respuesta final.
5. Escribe una prueba en tests/ que FALLE si la función no se llama.
6. Ajusta config/prompts.yaml para que el agente nunca confirme algo que la herramienta no devolvió como hecho.

RESTRICCIONES DURAS:
- Si la herramienta devuelve error, el agente NO confirma nada: dice que hubo un problema y ofrece pasar con una persona.
- NUNCA inventes datos que salen del otro sistema: horarios, folios, precios o disponibilidad.
- NINGUNA credencial en el código. Todas por variable de entorno.
- NO conectes contra mi sistema de producción sin avisarme antes.
- NO toques la verificación de firma, la deduplicación por id, ni el hecho de que el servidor contesta 200 antes de ponerse a trabajar. Si rompes eso, el proveedor reintenta hasta siete veces y mis clientes reciben la misma respuesta siete veces.

CRITERIO DE ACEPTACIÓN, compruébalo tú:
- La prueba nueva pasa, y vuelve a fallar si desconectas la llamada.
- python tests/test_local.py pasa.
- curl http://localhost:8000/ contesta "status":"ok".
- Un error simulado del otro sistema termina sin confirmación.

QUÉ REPORTAR AL FINAL:
Qué archivos tocaste, cómo se llama la herramienta, qué contesta si falla, y el resultado de cada criterio en una línea.

El que sigue es para otra cosa, y hay quien no lo abre nunca: cambiar de proveedor. Como en la entrevista se generó solo el adaptador del que elegiste, pasar de Zernio a Meta —o al revés— es escribir el otro desde cero. Guárdalo para el día que te mudes.

Prompt 10 · Cambiar de proveedor sin perder nada

Genera el adaptador nuevo con la misma interfaz, recoge las credenciales una por una y deja intactos tu prompt y tu historial.

Quiero cambiar de proveedor de WhatsApp. Hazlo tú de punta a punta.

CONTEXTO:
- Mi agente ya corre. El proveedor que uso hoy:
[ESCRIBE AQUÍ: zernio o meta]
- El proveedor al que me quiero pasar:
[ESCRIBE AQUÍ: zernio o meta]
- En la entrevista se generó SOLO el adaptador del que elegí; el del proveedor nuevo no existe todavía.
- Esto cambia por dónde entran y salen los mensajes, no lo que mi agente dice ni lo que ya conversó.

OBJETIVO:
Que el agente reciba y responda por el proveedor nuevo sin perder una sola conversación ni una línea de mi prompt.

QUÉ HACER, EN ESTE ORDEN:
1. Lee el adaptador que ya existe y anota su interfaz: qué métodos expone, qué recibe y qué devuelve.
2. Escribe el adaptador nuevo con esa MISMA interfaz. El resto del agente no se debe enterar del cambio.
3. Pídeme las credenciales del proveedor nuevo UNA POR UNA, diciéndome de qué pantalla sale cada una, y escríbelas en el .env.
4. Cambia WHATSAPP_PROVIDER al valor nuevo, en minúsculas.
5. Cuando el nuevo ya esté probado, borra el adaptador viejo y sus variables del .env.
6. Explícame en español qué cambia al dar de alta el webhook: la URL sigue terminando en /webhook, pero la firma viaja distinto. En Zernio llega en el encabezado X-Zernio-Signature, con el hex en minúsculas. En Meta llega en X-Hub-Signature-256, con el prefijo sha256= por delante.

RESTRICCIONES DURAS:
- NO toques config/prompts.yaml, config/business.yaml ni knowledge/.
- NO borres la base de datos ni el historial de conversaciones.
- NO dejes los dos adaptadores activos al mismo tiempo.
- NO des de baja el webhook viejo hasta que el nuevo esté probado con un mensaje real.
- NINGUNA credencial en el código.

CRITERIO DE ACEPTACIÓN, compruébalo tú:
- curl http://localhost:8000/ contesta "status":"ok".
- git ls-files | grep -c "^\.env$" devuelve 0.
- config/prompts.yaml y config/business.yaml quedaron sin cambios.

QUÉ REPORTAR AL FINAL:
Qué proveedor quedó activo, qué archivos creaste y borraste, los pasos que me tocan a mí en el panel del proveedor nuevo, y el resultado de cada criterio en una línea.

El último es el de todos los días. Cada vez que suba un precio, abras los sábados o quieras que salude más corto, es este el que copias, y no hace falta tocar nada de lo anterior.

Prompt 11 · Afinar el tono y enseñarle lo que falta

Ajusta prompts.yaml y business.yaml, mete los precios literales en knowledge/ y lo prueba con tres preguntas.

Quiero cambiarle el tono a mi agente y enseñarle lo que le falta. Hazlo tú.

CONTEXTO:
- Mi agente ya corre. Su personalidad vive en config/prompts.yaml y los datos de mi negocio en config/business.yaml.
- Lo que guardo en knowledge/ se incorpora al prompt del sistema.
- El tono que quiero:
[ESCRIBE AQUÍ: por ejemplo, más corto, de tú y sin tanto adorno]
- Lo que hoy no sabe y debería saber:
[ESCRIBE AQUÍ: por ejemplo, la lista de precios nueva y el horario de los sábados]

OBJETIVO:
Que conteste con mi tono y con mis datos nuevos, y que siga diciendo que no sabe cuando no sabe.

QUÉ HACER, EN ESTE ORDEN:
1. Ajusta el tono en config/prompts.yaml y los datos fijos en config/business.yaml.
2. Guarda los precios y los horarios como texto plano en knowledge/, un archivo por tema, e incorpóralos LITERALES al prompt: precios, horarios y condiciones no se resumen ni se redondean.
3. Deja escrita la regla de que, si no sabe algo, lo dice y ofrece pasar con una persona en vez de aproximar.
4. Corre tres pruebas y muéstrame las respuestas completas: una pregunta sobre el dato nuevo, una que le intente sacar un descuento, y una sobre algo que el agente no sabe.

RESTRICCIONES DURAS:
- NO subas nada de knowledge/ a GitHub: son datos de mi negocio.
- NO resumas ni redondees precios, horarios ni condiciones.
- NO inventes un dato que no esté en knowledge/ ni en config/.
- NO toques agent/ ni el .env.

CRITERIO DE ACEPTACIÓN, compruébalo tú:
- git check-ignore imprime la ruta de cada archivo de knowledge/.
- git ls-files knowledge/ muestra solo knowledge/.gitkeep.
- python tests/test_local.py pasa.
- En la prueba del descuento el agente no concede ninguno.

QUÉ REPORTAR AL FINAL:
Qué archivos tocaste, qué guardaste en knowledge/, las tres respuestas de prueba tal cual salieron, y el resultado de cada criterio en una línea.

Y si al final resulta que lo que necesitas es que además califique al cliente, agende y escriba en tu CRM, no lo cablees pieza por pieza: eso ya está resuelto en el AgentKit que cierra ventas.

15 · los números

Lo que cuesta de verdad, con la fecha en que se midió

Cada número de aquí abajo va con el día en que se consultó, y eso no es un adorno: estos precios se mueven, y el que más rápido se mueve es el de Meta. Si estás leyendo esto meses después, la fila de Meta es la primera que tienes que volver a mirar.

Las tarifas de Anthropic y los planes de Railway se verificaron el 17 de septiembre de 2026. Lo de WhatsApp con Meta trae una fecha más vieja, de agosto, porque esa es la fuente que hay.

Lo que te van a cobrar, pieza por pieza

El kit

Cuánto
Gratis. Licencia MIT
Consultado el
17-sep-2026

Railway · Trial

Cuánto
Un grant único de 5 USD. 1 GB de RAM, vCPU compartida y 5 servicios por proyecto
Consultado el
17-sep-2026

Railway · Free

Cuánto
0 USD al mes, con 1 USD de crédito de uso cada mes
Consultado el
17-sep-2026

Railway · Hobby

Cuánto
5 USD al mes, que ya incluyen 5 USD de uso
Consultado el
17-sep-2026

Railway · la letra chica de este proyecto

Cuánto
La base de datos es un segundo servicio encendido las 24 horas, y cuenta contra tu uso
Consultado el
17-sep-2026

Anthropic · al mes

Cuánto
Con Sonnet 5, 300 conversaciones salen ≈ 13 USD y 1.000 ≈ 44 USD. Con Haiku 4.5, ≈ 7 y ≈ 22 USD
Consultado el
17-sep-2026

WhatsApp con Zernio

Cuánto
Las 2 primeras cuentas conectadas son gratis y sin tarjeta. El número de pruebas no cuesta. Un número propio arranca en 3 USD al mes según el país
Consultado el
17-sep-2026

WhatsApp con Meta

Cuánto
Si el cliente escribió primero y contestas dentro de las 24 h, hoy ese mensaje no se cobra. Las plantillas sí: por mensaje entregado y por país, del orden de 0,01 USD en India a 0,025 en Estados Unidos
Consultado el
13-ago-2026

Ninguna de estas filas se inventó aquí: cada una es lo que decía la página de precios del proveedor el día de la tercera columna. Vuelve a comprobarlas antes de presupuestarle a un cliente.

Una línea sobre la ventana de 24 horas, porque es la que hace barata la parte de WhatsApp: mientras el cliente escriba primero y tú contestes dentro de ese día, hoy Meta no cobra esa respuesta, y este agente siempre responde. Cómo funciona y por qué casi nunca sales de ella está donde eliges proveedor.

El único número que puedes bajar tú mismo

El modelo lo eliges con la variable ANTHROPIC_MODEL y se cambia sin tocar nada más. Sonnet 5 es el que viene puesto:

Opus 5 · claude-opus-5

Entrada / salida por millón
5 / 25 USD
Por conversación de 8 idas y vueltas
≈ 0,11 USD

Sonnet 5 · claude-sonnet-5 · el que viene puesto

Entrada / salida por millón
2 / 10 USD
Por conversación de 8 idas y vueltas
≈ 0,04 USD

Haiku 4.5 · claude-haiku-4-5

Entrada / salida por millón
1 / 5 USD
Por conversación de 8 idas y vueltas
≈ 0,02 USD

La columna de la derecha no es una tarifa, es una cuenta: el volumen que trae el kit son 8 idas y vueltas, un prompt del sistema de unos 1.500 tokens, cerca de 16.000 tokens de entrada y 1.200 de salida. Ese volumen se midió contra el repo el 19 de agosto de 2026 y las tarifas el 17 de septiembre de 2026. Si tu prompt es más largo, tu número es más alto.

las tres cosas que mueven la cuenta

Por qué la factura no se parece a tu cantidad de mensajes

  • Tu agente no te cuesta por mensaje, te cuesta por token. En cada turno se le reenvía a Claude el prompt del sistema completo más el historial de esa conversación, así que el mensaje diez cuesta más que el primero, y cien personas preguntando sin comprar cuestan lo mismo que cien comprando.
  • El razonamiento interno del modelo cuenta contra ANTHROPIC_MAX_TOKENS, y esos tokens se cobran a la tarifa de salida, la más alta de las dos que trae la tabla de arriba. Aun así no son los que mandan en la factura: con ese mismo volumen, el grueso de lo que pagas es la entrada.
  • Las plantillas no salen en tu primera cuenta. Mientras solo contestes dentro de la ventana de 24 horas no hay plantilla que pagar; aparecen cuando eres tú quien escribe primero, y se cobran por mensaje entregado y por país.

Y la forma más efectiva de bajar todo esto no es cambiar de modelo: es no meter en el prompt información que tus clientes nunca preguntan. Cada línea de más se vuelve a pagar en cada turno de cada conversación.

ponlo en el calendario

1 de octubre de 2026

Hoy, si el cliente te escribió primero y contestas dentro de la ventana de 24 horas, Meta no cobra esa respuesta. Lo que se paga son las plantillas, por mensaje entregado.

Meta anunció que desde el 1 de octubre de 2026 pasa a cobrar por mensaje de negocio, e incluye respuestas que hoy salen gratis justamente por caer dentro de esa ventana.

Es un anuncio y aquí va sin cifra propia a propósito: la única cuenta que va a servir es la que esté publicada en la página de precios de Meta el día que la leas. Si tu agente vive de contestar, míralo antes de esa fecha y no después.

16 · preguntas frecuentes

Preguntas frecuentes

Doce preguntas que llegan cuando el agente ya está corriendo. Las que tienen dueño en otra sección se contestan en dos líneas y te mandan ahí.

¿Necesito saber programar?

No. Claude Code escribe el código; tú contestas preguntas sobre tu negocio en español.

Lo que haces a mano es pegar comandos y hacer clics en dos paneles. No abres un archivo de Python en ningún momento.

¿Puedo usarlo con mi negocio real?

Sí, después de probarlo en tu computadora. Tres cosas antes de apuntarle clientes de verdad.

Tu propio número, no el de pruebas, que caduca. PostgreSQL puesto en el despliegue, o el historial se borra en cada redespliegue. Y el secreto del webhook cargado, o cualquiera que sepa tu URL le puede inyectar mensajes al agente.

¿Y si el agente no sabe algo?

Depende de lo que tengas escrito en tu prompt del sistema. Esa regla —si no sabe algo, lo dice y ofrece pasar con una persona— no viene puesta de fábrica: se escribe en config/prompts.yaml.

Si aun así se inventó un precio, es que ese dato no está ni en la información del negocio ni en la carpeta knowledge. Ponlo en un archivo de texto dentro de knowledge y pídele a Claude Code que regenere el prompt del sistema.

Dejarla escrita es parte de afinar el agente: el prompt 11 de la sección 14 se la dicta a Claude Code junto con el tono y los datos que le falten.

¿Entonces agenda citas o no?

No por sí solo. Conversa, entiende y te deja los datos en el historial de la conversación: quién es, qué quiere y para cuándo.

Ejecutar la acción —reservar el horario, cobrar, descontar stock— es un cableado aparte, y eso lo resuelve la sección 14.

¿Puede escribirle primero a un cliente?

No de entrada, y no es un límite del kit: es la ventana de 24 horas de WhatsApp. Fuera de ese plazo hace falta una plantilla aprobada por Meta.

Como tu agente siempre responde, en la práctica nunca sale de la ventana; la regla completa está al elegir proveedor.

¿Cuánto cuesta?

El kit es gratis y de licencia MIT. Lo que se paga es el modelo por token, el servidor donde vive tu agente y, si usas un número propio, el número.

Las tarifas con su fecha, el costo por conversación y por qué la cuenta sube con el volumen están en la sección de costos.

¿Por qué mi repositorio de GitHub se ve casi vacío?

Porque no reemplazaste el .gitignore antes de subir. El que trae el kit excluye a propósito la carpeta del agente, su configuración, las pruebas, el archivo de dependencias y el Dockerfile: justo lo que el despliegue necesita.

Se arregla cambiando el .gitignore y volviendo a empujar, y el paso completo está en la sección 10. La comprobación es que git ls-files muestre agent/main.py y Dockerfile.

¿Puedo probar sin número de WhatsApp?

Sí, con el número de pruebas de Zernio. Tiene límites: 50 mensajes y 5 destinatarios distintos cada 24 horas, una sola sesión activa, y la que se activa dura 7 días.

Sirve para verlo funcionando, no para atender clientes; cómo se abre está en la sección 05.

¿Necesito Docker?

No. Railway construye la imagen en sus servidores, a partir del Dockerfile que te deja Claude Code.

Si no tienes Docker instalado, no te trabes ahí: no lo vas a correr en tu máquina.

¿Qué pasa con mis datos?

Tu agente corre en tu infraestructura: tu servidor, tu base de datos y tus llaves. El kit no tiene backend propio ni telemetría, así que del lado del kit nadie ve tus conversaciones.

Pasar, pasan por dos lugares más, y con este kit no se evitan: por tu proveedor —Zernio tiene su propia bandeja de conversaciones; con Meta van por su Cloud API— y por la API de Anthropic, que es la que escribe cada respuesta con tu llave.

Los archivos de la carpeta knowledge no salen de tu máquina: el .gitignore los deja fuera de GitHub. Lo que sí viaja es su contenido, porque durante la entrevista se incorpora literal al prompt del sistema, y ese archivo —config/prompts.yaml— sí sube a tu repositorio. Si hay algo que no quieres ni en tu repositorio privado, no lo pongas en knowledge.

¿Puedo tener varios agentes?

Sí: un clon del kit por negocio. Cada uno con su número, su secreto del webhook, su repositorio y su servicio.

Lo que nunca se comparte es la base de datos. Aquí abajo está el prompt que monta el segundo sin tocar el primero.

¿Cuál es la diferencia con la guía del Closer?

Esta contesta; aquella cierra. El agente de aquí conversa, entiende y te deja los datos.

Si la venta se cierra por chat y necesitas calificar al cliente, agendar y escribir en tu CRM, el AgentKit que cierra ventas son quince fases y una compuerta de chequeos: otra guía, y bastante más larga.

Montar un segundo agente sin tocar el primero

Un negocio, un clon. El riesgo no es clonar: es que los dos terminen apuntando al mismo lado y se pisen.

Lo que no se comparte

Cuatro cosas tienen que ser distintas entre los dos

  • El número de WhatsApp: cada agente atiende el suyo.
  • El secreto del webhook, que lo inventas tú: uno por agente, nunca copiado del otro.
  • El repositorio de GitHub y el servicio donde lo despliegas.
  • La base de datos. Dos instancias contra la misma base le contestan dos veces a la misma persona.

Prompt 12 · Clonar el kit para un segundo negocio

Deja la carpeta nueva lista para su propia entrevista y comprueba que la del primer agente no cambió. No corre /build-agent: eso lo decides tú después.

Quiero montar un SEGUNDO agente de WhatsApp para otro negocio sin tocar el que ya tengo. Hazlo tú.

CONTEXTO:
- Ya tengo un agente hecho con whatsapp-agentkit en esta carpeta, y no se toca.
- El segundo sale de un clon aparte del mismo repositorio público: https://github.com/Hainrixz/whatsapp-agentkit.git
- La carpeta nueva va al mismo nivel que esta, no adentro: [ESCRIBE AQUÍ: el nombre, por ejemplo mi-agente-2]

OBJETIVO:
Dejar el segundo clon listo para su entrevista, con el primero intacto.

QUÉ HACER, EN ESTE ORDEN:
1. Sal de esta carpeta y clona el repositorio en la nueva.
2. En la carpeta nueva corre bash start.sh y dime qué verificó: Python 3.11 o superior, que claude esté en el PATH, la carpeta knowledge y la copia de .env.example a .env.
3. Comprueba que la carpeta del primer agente no cambió y dímelo.
4. Hazme la lista de lo que tiene que ser distinto entre los dos: número de WhatsApp, secreto del webhook, repositorio de GitHub, servicio de despliegue y base de datos.

RESTRICCIONES DURAS:
- NO modifiques ningún archivo del primer agente.
- NO copies el .env del primero al segundo.
- NO reutilices el webhook, el secreto ni la base de datos del primero: dos instancias contra la misma base le contestan dos veces a la misma persona.
- NO corras /build-agent todavía. Esto solo deja la carpeta lista.

CRITERIO DE ACEPTACIÓN, compruébalo tú:
- La carpeta nueva existe y es hermana de esta, no está dentro.
- Dentro de ella hay CLAUDE.md, start.sh, .env y la carpeta knowledge.
- git status en la carpeta del primer agente no muestra cambios.
Si alguno falla, arréglalo y vuelve a comprobar.

QUÉ REPORTAR AL FINAL:
La ruta de la carpeta nueva, qué verificó start.sh, la confirmación de que el primer agente no fue tocado, y la lista del punto 4.

Revisar el kit con su propio auditor

El kit trae un script que se revisa a sí mismo: seis chequeos sobre el repositorio. Sirve cuando algo no cuadra y quieres descartar que el problema venga de ahí.

Prompt 13 · Correr el auditor y que te lo traduzcan

Corre scripts/audit.py y te devuelve los seis chequeos en español, uno por línea. Es un diagnóstico: no arregla nada y no sube nada.

Corre el auditor del kit y explícame el resultado en español. No arregles nada.

CONTEXTO:
- Estoy dentro del clon de whatsapp-agentkit y no programo: la salida de ese script en crudo no me dice nada.
- El script es scripts/audit.py y hace seis chequeos sobre el kit. Sale con código 1 si alguno falla.
- El chequeo de enlaces necesita conexión y se puede saltar con la bandera --skip-links.

OBJETIVO:
Saber si el kit está sano y, si no lo está, qué es lo que falla.

QUÉ HACER, EN ESTE ORDEN:
1. Corre python3 scripts/audit.py.
2. Si falla por conexión o se queda colgado en los enlaces, vuelve a correrlo con python3 scripts/audit.py --skip-links y avísame que ese chequeo quedó sin correr.
3. Tradúceme los seis chequeos, uno por línea, con pasó o falló: que compilen los bloques de código de CLAUDE.md, que el YAML se entienda, que no queden rastros de los proveedores retirados, que toda variable de entorno usada esté documentada en .env.example, que los enlaces del README respondan, y que las imágenes existan y midan al menos 600 px de ancho.
4. Si alguno falló, dime en una línea qué significa eso para mí.

RESTRICCIONES DURAS:
- NO arregles nada. Esto es un diagnóstico, no una reparación.
- NO instales dependencias sin avisarme. La única excepción es pyyaml si el script se queja de que falta: pídemelo y espera mi sí.
- NO subas nada a GitHub ni hagas ningún commit.

CRITERIO DE ACEPTACIÓN, compruébalo tú:
- Me diste los seis chequeos, cada uno con pasó o falló.
- Si usaste --skip-links, lo dijiste explícitamente.
- git status muestra lo mismo que antes de correr el script.

QUÉ REPORTAR AL FINAL:
Con qué código salió el script, los seis chequeos traducidos uno por línea, y qué tengo que hacer yo, si es que hay algo.

Si tu pregunta es un síntoma concreto —dice degradado, no llega nada, el agente se olvida de todo—, está en la tabla de la sección 13, con su causa y su arreglo.

Guía de la bóveda

Lo que te queda cuando cierras esta página

Un número de WhatsApp que contesta a cualquier hora, escrito por Claude Code en tu computadora a partir de diez respuestas tuyas, corriendo en un servidor que no es tu máquina y con el historial de cada conversación guardado en una base que sobrevive a los redespliegues.

También te queda claro dónde está el límite, que es lo que casi nadie dice en voz alta: tu agente conversa, entiende y deja los datos escritos en el historial. Agendar, cobrar o descontar inventario es un cableado aparte, y la sección 14 te lo deja hecho con un prompt.

Y sabes en qué se te va el dinero: no en mensajes, en tokens. Cada turno le reenvía a Claude el prompt del sistema completo —el que lleva los datos de tu negocio— más el historial, así que el mensaje diez cuesta más que el primero. Bajarlo no es cambiar de modelo, es sacar del prompt lo que tus clientes nunca preguntan.

Lo que esta guía no repite

Lo que promete esta página

Que cada comando, cada ruta de menú y cada nombre de variable salieron del kit tal como está hoy, y que los precios y los límites se verificaron el 17 de septiembre de 2026. Lo que no promete es que sigan iguales: Meta anunció un cambio para el 1 de octubre de 2026 —cobrar por mensaje de negocio, incluidas respuestas que hoy no se cobran— que conviene confirmar en su página de precios el día que leas esto, y los paneles de Zernio y Railway se mueven sin avisar. Si lo que ves en tu pantalla no coincide con lo que dice aquí, manda tu pantalla.

Lo nuevo sale primero en Instagram

Ahí publico lo que voy probando antes de que termine convertido en una guía como esta.

@soyenriquerocha