# Tu propio CRM con WhatsApp e Instagram, de cero a publicado > Guía de Jaime Herrera (VisiumAI) · versión 2026-10-25 · https://visiumai.com/guias/crm-whatsapp.md ## Para ti Mi agencia vende y da seguimiento con un CRM que construí con Claude Code, y los mensajes de WhatsApp e Instagram de mi negocio llegan ahí y los contesto desde ahí, mientras el WhatsApp sigue funcionando en mi celular como siempre. Con esta guía, tu agente hace lo mismo para tu negocio, de principio a fin: 1. **Te entrevista** sobre tu empresa y arma un plan con las funciones que de verdad usas. 2. **Lo diseña** con tu marca y con referencias que te gusten, para que no se vea como cualquier otra cosa hecha con IA. 3. **Lo construye:** contactos, empresas, tratos en un tablero, notas, documentos, reportes, o lo que salga de la entrevista. 4. **Lo publica** en tu VPS o en Vercel, con HTTPS y respaldos. 5. **Le conecta tus bandejas** de WhatsApp e Instagram con [Zernio](https://zernio.com): sin crear una app de Meta, sin su proceso de verificación y con coexistencia (tu número sigue en la app de WhatsApp Business del celular, y lo que contestes ahí también aparece en el CRM). **Lo que cuesta:** - **Tu agente:** una suscripción que lo incluya (con Claude Code, desde el plan Pro). - **Dónde publicarlo:** un VPS (yo uso uno de Hostinger, donde también tengo otras apps) o Vercel. El plan gratis de Vercel es solo para proyectos personales; para un negocio va el de paga. - **Dominio:** opcional, unos 10 dólares al año. Sin dominio también funciona. - **Zernio:** las primeras 2 cuentas son gratis (un WhatsApp y un Instagram); de la tercera en adelante, 6 dólares al mes por cuenta. - **Meta:** cobra aparte, directo a tu cuenta de WhatsApp Business, los mensajes de plantilla, es decir, los que mandas fuera de las 24 horas desde el último mensaje del cliente. Contestar dentro de esas 24 horas y recibir mensajes no cuesta. **Lo que conviene saber:** tus mensajes pasan por los servidores de Zernio para llegar a tu CRM. Para tu propio negocio es un buen trato. Si vas a montarle esto a un cliente, platícalo con él antes. **Qué necesitas:** un agente que use la terminal de tu computadora (Claude Code, Codex u otro parecido), una cuenta de GitHub, tu VPS o una cuenta de Vercel, tu número en la app **WhatsApp Business** (versión 2.24.17 o más nueva) y una cuenta **profesional** de Instagram. **Cómo usarla:** crea una carpeta vacía para tu CRM, abre tu agente ahí y pégale esto: > Lee completa https://visiumai.com/guias/crm-whatsapp.md y sigue la guía paso a paso. Te va a entrevistar, te mostrará un plan y esperará tu OK antes de construir. Trabaja por fases y te avisa al terminar cada una. Según cuántas funciones pidas, toma de una tarde a un par de días, y puedes hacerlo en varias sesiones. --- ## Para el agente Vas a construir, publicar y conectar un CRM a la medida para la persona con la que trabajas. Sigue las fases en orden. ### Reglas de ejecución 1. **Lee la guía completa antes de empezar.** Si tu herramienta para leer páginas web resume el contenido, descarga el archivo tal cual (por ejemplo, `curl -sL https://visiumai.com/guias/crm-whatsapp.md`). 2. **Por fases, con punto de control.** Al terminar cada fase, dile a la persona qué quedó, qué puede probar y qué sigue, y espera su OK. Si la sesión se corta, anota en `PROGRESO.md` en qué fase vas para retomar. 3. **Solo lo que salió en la entrevista.** Nada de funciones "por si acaso". Lo que la persona quiera después va a una lista de pendientes en el plan. 4. **Credenciales fuera del chat.** Contraseñas, tokens y llaves van en `.env` (en `.gitignore`) y en el servidor. Las de servicios externos las pega la persona; las que generes tú (secretos de sesión, del webhook) escríbelas directo al archivo con un comando, sin mostrarlas. La llave **privada** SSH nunca sale de la computadora ni se muestra. 5. **El servidor puede tener otras apps.** Antes de instalar nada en un VPS, revisa qué corre ahí. No detengas, borres ni reconfigures lo que ya existe; si hace falta tocar algo compartido (el proxy, un puerto), pregunta antes. 6. **No mandes mensajes a nadie por tu cuenta.** Las pruebas de envío van al número o a la cuenta que la persona indique, y solo cuando ella lo pida. 7. **Cuida lo que imprimes.** Al conectar el WhatsApp, Zernio trae el historial de la app a su propia bandeja, y ahí puede haber datos sensibles. Para depurar, imprime solo datos de control (fechas, dirección, estado), nunca el texto de los mensajes. 8. **Usa git desde el principio** y haz un commit al cerrar cada parte que funcione. 9. **Usa el idioma de la persona** para hablarle y para todo el CRM. ### Fase 1. Entrevista Haz estas preguntas en un solo mensaje y dile que puede contestar con audio transcrito o a grandes rasgos: 1. **Tu negocio:** qué vendes, a quién y cuántas personas trabajan contigo. 2. **Quién lo va a usar:** solo tú o tu equipo. Si es un equipo: cuántos, qué hace cada quien y si cada uno debe ver solo lo suyo. 3. **Cómo vendes hoy:** los pasos desde que llega un prospecto hasta que te paga. ¿Hay más de un proceso (ventas, proyectos en curso, renovaciones)? 4. **Qué guardas:** de cada cliente, de cada empresa y de cada trato (valor, moneda, fechas, mensualidad, de dónde llegó…). 5. **Por dónde te llegan:** WhatsApp, Instagram, Facebook, correo, formulario web, teléfono. 6. **¿Ya usas un CRM?** Cuál (HubSpot, Pipedrive, GoHighLevel, Zoho, Salesforce, Kommo…) y qué datos quieres traer: contactos, empresas, tratos, notas, archivos. Si no usas CRM, ¿dónde vive hoy esa información (Excel, Google Sheets, una libreta)? 7. **Qué quieres ver de un vistazo:** ventas del mes, conversión, tratos estancados, lo que se cobra este mes… 8. **Tu marca:** logo, colores y 2 o 3 sitios o apps cuyo diseño te guste (capturas o enlaces). 9. **Dónde lo vas a publicar:** ¿ya tienes un VPS (de qué proveedor) o prefieres Vercel? ¿Tienes dominio? 10. **Idioma y moneda.** **Si ya usa un CRM,** antes de armar el plan investiga cómo sacar sus datos, en este orden de preferencia: 1. **API pública:** busca en la documentación oficial del CRM si tiene una, qué datos expone (contactos, empresas, tratos, notas, actividades, archivos), cómo se autentica (token personal o app) y qué plan la incluye: en algunos CRM la API solo viene en los planes de paga. 2. **Exportación nativa:** si no hay API o no la incluye su plan, revisa qué exporta el propio CRM (CSV o Excel) y qué se queda fuera, como notas, archivos o el historial. 3. **Copia manual:** solo como último recurso, y solo con los datos que la persona diga. Dile qué encontraste, qué se puede traer y qué no, y qué le tocará hacer a ella (crear el token, descargar el archivo). Si su suscripción está por vencer, que exporte **antes** de cancelarla: después ya no se puede. La migración entra al plan como un módulo más. ### Fase 2. Plan Con las respuestas, muestra un plan corto y espera el OK: - **Lo que entra ahora:** de 4 a 6 módulos como máximo. Una base que suele servir: contactos, empresas, tratos en un tablero por etapas (arrastrar y soltar), notas y documentos en cada registro, reportes, y la bandeja de WhatsApp e Instagram (fases 6 a 8). - **Lo que queda para después:** todo lo demás que salió en la entrevista. - **Las etapas de cada proceso,** con los nombres que usó la persona. - **Acceso:** un solo usuario (contraseña guardada como hash en `.env` y sesión en una cookie firmada) o usuarios con roles, si es un equipo. - **Stack:** si la persona no tiene preferencia, Next.js (App Router) + TypeScript + Tailwind + Prisma + PostgreSQL. Es lo que uso y corre igual en un VPS (Docker) que en Vercel. - **Dónde se publica** (fase 5) y qué le tocará hacer a la persona. ### Fase 3. Diseño Antes de construir las pantallas, define la dirección visual con la skill **frontend-design** de Anthropic. Dale a la persona este enlace para que sepa qué vas a usar: **https://github.com/anthropics/claude-plugins-official/tree/main/plugins/frontend-design** - **Si eres Claude Code:** pídele a la persona que corra `/plugin install frontend-design@claude-plugins-official` (o que la busque en `/plugin`) y que reinicie la sesión si hace falta. Después úsala en todo el trabajo de interfaz. - **Si eres otro agente:** lee la skill completa y aplícala tal cual: `https://raw.githubusercontent.com/anthropics/claude-plugins-official/main/plugins/frontend-design/skills/frontend-design/SKILL.md` **Fuentes de inspiración** (compártelas con la persona y pídele capturas de lo que le guste): | Sitio | Para qué | |---|---| | https://dribbble.com/ | Diseños de CRM y paneles: busquen "CRM dashboard" o "inbox" | | https://recent.design/ | Sitios recientes con diseño cuidado (antes se llamaba godly.website) | | https://www.awwwards.com/ | Sitios premiados por su diseño | | https://a1.gallery/ | Galería de interfaces | | https://21st.dev/ | Componentes ya hechos (React + Tailwind); copia la idea, adáptala al proyecto | Cómo trabajarlo: 1. Con la marca y las referencias, propón la dirección en 3 o 4 líneas: paleta, tipografías, densidad y el detalle que la hará reconocible. Espera el OK. 2. Diseña primero **una sola pantalla** (el tablero de tratos o la bandeja), muéstrasela con una captura y ajusta. 3. Cuando la apruebe, extiende el estilo al resto. Revisa cada pantalla en escritorio y en celular. ### Fase 4. Construye el CRM 1. Crea el proyecto con el stack del plan, el esquema de la base de datos y el acceso. 2. Construye los módulos aprobados, uno a la vez, con commit al cerrar cada uno. 3. Para probar en local, levanta PostgreSQL con Docker o, si no hay Docker, con `npx prisma dev` (crea un Postgres local sin instalar nada; usa su URL TCP con `pgbouncer=true`). 4. Llena la base con datos de ejemplo inventados para que la persona pueda probar, y bórralos antes de publicar si ella lo pide. 5. **Migración** (si hay datos que traer): un script que lea de la API o del archivo exportado y que se pueda correr dos veces sin duplicar. Guarda en cada registro el id que tenía en el CRM anterior (por ejemplo, `idOrigen`, único) para empatarlo. Primero corre una prueba con unos cuantos registros, muéstrale el resultado a la persona y después importa todo. Guarda una copia del export original fuera del repo (no se versiona: trae datos de clientes). 6. **Punto de control:** la persona recorre el CRM en local y te dice qué cambiar. ### Fase 5. Publícalo Elige el camino según la entrevista. #### Camino A: tu propio VPS (por ejemplo, Hostinger) La persona no tiene que configurar el servidor: tú haces todo por SSH. Lo único que hace ella es autorizar tu llave una vez. 1. **Genera una llave SSH solo para este proyecto:** `ssh-keygen -t ed25519 -C "crm-deploy" -f ~/.ssh/crm_vps -N ""` Muéstrale únicamente la llave **pública** (`~/.ssh/crm_vps.pub`). 2. **La persona la autoriza:** la pega en el panel de su proveedor, en la sección de llaves SSH del VPS (en Hostinger está en la administración del VPS), y te da la IP y el usuario (casi siempre `root`) que aparecen en el resumen del servidor. 3. **Configura la conexión:** agrega un alias en `~/.ssh/config` (`Host crm-vps`, con `HostName`, `User` e `IdentityFile ~/.ssh/crm_vps`) y prueba `ssh crm-vps "uname -a"`. 4. **Revisa el servidor antes de tocarlo:** sistema, si tiene Docker, qué contenedores corren, qué usa los puertos 80 y 443 y si ya hay un proxy con HTTPS automático (Traefik, Caddy o nginx). Hostinger ofrece una plantilla con Docker y Traefik. 5. **Despliega con Docker Compose** en su propia carpeta (por ejemplo, `/root/crm`): la app y su PostgreSQL (o una base dedicada en un Postgres que ya exista), sin exponer el puerto de la base a internet. Si ya hay un proxy, únete a su red y publícalo con sus etiquetas; si no hay, pon Caddy, que saca el certificado HTTPS solo. Al arrancar, el contenedor aplica las migraciones (`prisma migrate deploy`). 6. **El `.env` de producción** se crea en el servidor con permisos 600 y secretos nuevos, distintos a los de local. 7. **Dominio:** la persona crea un registro A (por ejemplo, `crm.sudominio.com`) que apunte a la IP del VPS; tú le das los datos exactos. Sin dominio, usa un nombre gratuito que apunte a la IP, como `.sslip.io`, para tener HTTPS igual. 8. **Respaldos:** una tarea `cron` nocturna con `pg_dump` de la base y una copia de los documentos subidos, que conserve 14 días. 9. **Para actualizar:** manda el código (`git archive HEAD | ssh crm-vps "tar -x -C /root/crm"` o `git pull` si el servidor tiene el repo) y corre `docker compose up -d --build`. Anótalo en el README. #### Camino B: Vercel 1. Sube el proyecto a un repositorio privado de GitHub. La persona inicia sesión en GitHub cuando se lo pidas. 2. Conecta el repo en Vercel (la persona inicia sesión; con la CLI, `npx vercel link`). 3. **Base de datos:** Vercel no trae una. Usa un PostgreSQL administrado (Neon desde el Marketplace de Vercel, o Supabase) y aplica las migraciones en el build (`prisma migrate deploy && next build`). 4. **Documentos subidos:** Vercel no guarda archivos en disco entre peticiones. Usa Vercel Blob o el almacenamiento de Supabase. 5. **Variables de entorno:** en el proyecto de Vercel, sin mostrarlas (con la CLI puedes pasarlas desde el `.env`). 6. **Dominio:** Vercel da uno `*.vercel.app` con HTTPS; si la persona tiene dominio, se agrega en el proyecto. 7. Recuérdale que el plan gratis de Vercel es solo para uso personal. **Punto de control:** la persona entra al CRM publicado desde su celular, con datos móviles, e inicia sesión. ### Fase 6. La bandeja de WhatsApp e Instagram Agrega al CRM un webhook que recibe los mensajes que manda Zernio, dos tablas, una pantalla para leerlos y contestarlos, y el envío de respuestas por la API de Zernio. Las cuentas se conectan en la fase 7: esta fase no las necesita. **Tablas** (adapta los nombres al proyecto): - **Conversación:** `canal` (`whatsapp` o `instagram`) · `zernioConversationId` (único: el `conversation.id` del webhook; con él se responde) · `zernioAccountId` (el `account.id`; la API lo pide al enviar y cambia si la cuenta se reconecta, así que actualízalo con cada mensaje) · `participanteId` (en WhatsApp, el teléfono sin "+"; en Instagram, el id de la persona) · `nombre`, `usuario`, `telefono` (E.164, solo WhatsApp) · `contactoId` opcional · `noLeidos` · `ultimoMensajeEn`. - **Mensaje:** `conversacionId` · `direccion` (`entrante` o `saliente`) · `texto` · `adjuntos` (solo el tipo: `image`, `audio`, `video`, `file`, `sticker`, `share`; no guardes las URL, caducan) · `platformMessageId` (único: el id del mensaje en Meta, la clave para no duplicar) · `origen` (`crm`, o el `source` del webhook: `whatsapp_business_app` cuando se contestó desde el celular) · `enviadoEn` (el `sentAt`; ordena el hilo). **El webhook:** una ruta `POST` pública, por ejemplo `/api/zernio/webhook`, fuera del login de la app. 1. **Firma.** Lee el cuerpo **crudo** antes de parsearlo. `X-Zernio-Signature` es el HMAC-SHA256 en hexadecimal de ese cuerpo con `ZERNIO_WEBHOOK_SECRET`. Compáralo en tiempo constante (`crypto.timingSafeEqual` en Node). Sin firma o con firma distinta, responde 401 y no proceses nada. 2. **Qué guardar.** Solo `message.received` y `message.sent` con `message.platform` igual a `whatsapp` o `instagram`. Todo lo demás, incluido el evento de prueba `webhook.test`, se responde con 200 y se ignora. 3. **Valida la forma** (por ejemplo, con zod). Si un evento de mensaje no trae lo esperado, responde 400: queda en los registros de Zernio y se puede reenviar después de corregir. 4. **Sin duplicados.** Zernio reintenta hasta 7 veces y puede mandar el mismo evento dos veces. Crea el mensaje con `platformMessageId` único y, si ya existe, responde 200 sin hacer nada más. Responde siempre en menos de 5 segundos. 5. **De quién es cada dato.** En `message.sent` el `sender` es la propia cuenta de la persona, no el cliente: los datos del cliente salen de `conversation.participantId`, `participantName` y `participantUsername`. En `message.received` sí puedes usar `sender.name` y `sender.phoneNumber`. 6. **No leídos.** Un entrante suma 1. Un saliente, venga de donde venga, deja la conversación en 0. 7. **Ligar al contacto.** En WhatsApp, busca el contacto cuyo teléfono coincida en los **últimos 10 dígitos**: así empatan "+52 1 614…", "52614…" y "614…". Instagram no trae teléfono: se liga a mano desde la pantalla. **Responder desde el CRM:** ``` POST https://zernio.com/api/v1/inbox/conversations/{zernioConversationId}/messages Authorization: Bearer $ZERNIO_API_KEY Content-Type: application/json { "accountId": "", "message": "texto" } ``` - La respuesta trae `data.messageId`, el id del mensaje en Meta. Guárdalo con **upsert** sobre `platformMessageId`: en Instagram, el aviso del webhook (`message.sent`) puede llegar antes que la respuesta de la API. - Si Zernio responde con error, muestra su mensaje tal cual en la pantalla. - **Ventana de 24 horas:** Meta solo deja mandar texto libre dentro de las 24 horas desde el último mensaje del cliente; fuera de ella, WhatsApp exige una plantilla aprobada. Muestra un aviso cuando la ventana esté cerrada. - Con esta guía solo se responde texto. Plantillas y archivos quedan para después. **La pantalla:** - Lista de conversaciones por fecha, con el canal y los no leídos; el total de no leídos, en el menú. - El hilo abierto, con caja de respuesta (Enter envía; Shift+Enter, salto de línea) y una etiqueta en los salientes que vinieron del celular. - Ligar la conversación a un contacto existente o crear el contacto con lo que se sabe (nombre y teléfono). En la ficha del contacto, enlaces a sus conversaciones. - Que los mensajes nuevos aparezcan solos: un refresco cada pocos segundos basta. **Prueba en local.** Zernio no puede llegar a `localhost`: prueba el webhook con eventos simulados, firmados con el mismo HMAC. - Sin firma o con firma mala: 401. - Un mensaje entrante nuevo: se crean la conversación y el mensaje, y el contacto se liga si el teléfono coincide. - El mismo evento otra vez: 200, sin duplicar. - Un `message.sent` con `source: "whatsapp_business_app"`: aparece como enviado desde el celular y los no leídos vuelven a 0. - Un evento de otra red (por ejemplo, `telegram`): 200 e ignorado. Publica esta fase igual que la fase 5. ### Fase 7. Conecta tus cuentas en Zernio (las conecta la persona) Guía a la persona en el navegador; tú no inicias sesión por ella. 1. Crea la cuenta en zernio.com. 2. **WhatsApp con coexistencia:** en Zernio, conectar WhatsApp. En la ventana de Meta elige **"Connect existing WhatsApp Business app account"** (conectar la cuenta de la app de WhatsApp Business que ya existe) y escanea el código QR con la app del celular. Si el número ya está conectado a otro proveedor de la API de WhatsApp, desconéctalo primero desde la app: Ajustes → Cuenta → Business Platform → Desconectar. 3. **Instagram:** conectar Instagram con la cuenta profesional y aceptar los permisos de mensajes. 4. **API key:** en https://zernio.com/dashboard/api-keys → **Create API key**, con el grupo de recursos `messages` activado (sin él, la bandeja responde 403). La persona la pega en el `.env` local como `ZERNIO_API_KEY`; tú la copias al servidor sin mostrarla. 5. **Verifica sin mostrar la llave:** `GET https://zernio.com/api/v1/accounts` con `Authorization: Bearer $ZERNIO_API_KEY` debe devolver las dos cuentas. Para WhatsApp, `GET /v1/accounts/{accountId}/health` debe traer `platformConnection.status: "connected"` e `inboundWebhookSubscribed: true`. ### Fase 8. Registra el webhook y haz la prueba real 1. Genera `ZERNIO_WEBHOOK_SECRET` directo en el `.env` del servidor (en Vercel, en sus variables) y reinicia la app. 2. Registra el webhook desde el servidor, para que el secreto no pase por el chat: ``` POST https://zernio.com/api/v1/webhooks/settings { "name": "CRM", "url": "https:///api/zernio/webhook", "secret": "", "events": ["message.received", "message.sent"] } ``` 3. Manda el evento de prueba con `POST /v1/webhooks/test` y el `webhookId` que devolvió el paso anterior. Tu CRM debe contestar 200. 4. **Prueba real:** pide a la persona que mande un WhatsApp a su número desde otro teléfono y un mensaje directo a su Instagram desde otra cuenta, que conteste uno desde el CRM y otro desde el celular. Revisa que todo aparezca. ### Si algo falla **Al publicar:** - **`Permission denied (publickey)`:** la llave pública no quedó autorizada en el VPS o el alias no apunta a `~/.ssh/crm_vps`. Pide a la persona que revise el panel. - **El certificado HTTPS no sale:** el registro DNS todavía no apunta a la IP (puede tardar unos minutos) o el puerto 80 lo ocupa otra app. Revisa con `dig` o `nslookup` antes de reintentar. - **En Vercel no conecta a la base:** la URL de la base no está en las variables del entorno de producción, o le falta `sslmode=require`. **Con Zernio:** - **El webhook responde 401 con mensajes reales:** el secreto del servidor no es el que se registró, o el cuerpo se parseó antes de calcular la firma. - **No llegan mensajes:** revisa `GET /v1/webhooks/logs` (cada intento con su código) y el `health` de la cuenta (fase 7). - **No aparece el historial anterior:** es normal. Solo los mensajes nuevos llegan por webhook; lo viejo se puede leer con `GET /v1/inbox/conversations` si la persona lo quiere importar. - **WhatsApp responde `(#200) You do not have the necessary permission`:** el número tiene verificación en dos pasos. Registra el número otra vez con su PIN (endpoint de registro de número de Zernio). - **Instagram responde 409 `not_thread_owner`:** otra app tiene el control de esa conversación. Se recupera con el endpoint de control de conversación de Zernio. - **La API responde 403 en la bandeja:** la API key no tiene activado el grupo `messages`. Crea otra con él. --- ## Para ti: cómo sacarle provecho - **Empieza chico.** Lo que uses todos los días en las primeras dos semanas te dice qué construir después. - **Contesta desde donde estés.** En la oficina, desde el CRM; en la calle, desde el celular. El hilo es el mismo. - **Liga cada conversación a su contacto.** Al abrir la ficha de un cliente ves sus tratos, sus notas y lo que te escribió. - **Pídele mejoras a tu agente como se las pedirías a un empleado:** "agrega un campo de fecha de cobro", "avísame de los tratos que llevan 10 días sin moverse". - **Si lo vas a vender a clientes,** piensa en la privacidad: con Zernio los mensajes pasan por un tercero. Para hacerlo sin intermediario hay que registrarse como Tech Provider de Meta, que es más trámite pero te da el control total. --- Guía de **Jaime Herrera**, VisiumAI (visiumai.com). Publico sobre automatización con IA en YouTube (youtube.com/@jaime_herrerag) e Instagram (@jaimeherrera.ia).