Dev

Webhook de WhatsApp no llega: localhost, ngrok y n8n

Cuando el webhook de WhatsApp no llega, la causa casi siempre está en uno de cinco lugares: la URL no es pública, el HTTPS falla, el evento correcto no está activado, el endpoint responde lento o con error, o n8n tiene la URL de prueba. Puedes descubrir cuál es en pocos minutos, en ese orden, usando el endpoint de prueba y la lista de entregas recientes de la API. Esta guía sigue ese orden, con los comandos.

Publicado el · 7 min de lectura

Este artículo también está disponible en: Português · English

¿Por dónde empezar el diagnóstico?

Separa el problema en dos preguntas. La primera: ¿el evento está saliendo de ZapZap? La segunda: ¿llega a tu sistema y se procesa? La API responde la primera con la lista de entregas recientes, que muestra por evento si fue entregado, el status HTTP y la latencia. Si la lista está vacía para mensajes reales, el problema está antes del envío (evento apagado o instancia desconectada). Si hay entregas con status de error, el problema está en tu endpoint.

Antes que nada, confirma la instancia. Consulta el status de la instancia: si no está conectada, no hay mensajes nuevos que generen eventos. Después confirma la configuración con ver webhook: la URL, si está habilitado y qué eventos están seleccionados.

Quatro comandos de diagnóstico

BASE="https://api.zapzapapi.com/api/v1"
H1="x-api-key: $ZAPZAP_API_KEY"
H2="x-api-secret: $ZAPZAP_API_SECRET"

curl "$BASE/$INSTANCE_ID/instance/status" -H "$H1" -H "$H2"                     # conectada?
curl "$BASE/instances/$INSTANCE_ID/webhook" -H "$H1" -H "$H2"                   # URL, enabled, events
curl "$BASE/instances/$INSTANCE_ID/webhook/deliveries?limit=20" -H "$H1" -H "$H2" # o que saiu e com qual status
curl "$BASE/$INSTANCE_ID/webhook/errors" -H "$H1" -H "$H2"                      # motivos de falha

¿Puedo usar localhost o 127.0.0.1 como URL del webhook?

No. El servidor de ZapZap está en internet y no ve tu máquina. Además, la API rechaza direcciones locales y privadas al guardar la configuración (localhost, 127.0.0.1, 192.168.x.x y similares), así que la llamada de configuración ya devuelve un error de validación. La URL tiene que ser HTTPS, pública y accesible desde afuera.

Al guardar, la API también hace una verificación de alcance sobre tu URL (una solicitud HEAD con un límite de tiempo corto). Cualquier respuesta HTTP, incluso 404 o 405, cuenta como alcanzable. Si el servidor no responde en ese plazo, la configuración falla con un mensaje de URL inaccesible. Si recibiste ese error, el endpoint estaba caído, detrás de un firewall o demasiado lento en ese instante.

¿Cómo probar en local con ngrok u otro túnel?

Un túnel publica tu puerto local en una URL HTTPS pública. El flujo es: levanta el servidor, abre el túnel apuntando al puerto, copia la URL HTTPS generada y configúrala como webhook_url. Herramientas como ngrok y cloudflared (Cloudflare Tunnel) hacen esto. Cada una tiene sus reglas de cuenta y de URL, así que revisa su documentación.

Dos trampas comunes. Primera: la URL del túnel cambia cuando reinicias (en planes sin dominio fijo), y el webhook configurado pasa a apuntar al vacío. Reconfigúralo cada vez que levantes un túnel nuevo. Segunda: un túnel detenido o el servidor local caído generan fallas, y las fallas seguidas pueden desactivar el webhook.

Para validar el camino completo, usa la prueba de webhook justo después de configurar. Envía un evento firmado y devuelve status y latencia. Si la prueba funciona y los mensajes reales no, vuelve al punto de los eventos activados.

Subir o túnel e configurar a URL (exemplo com ngrok)

# terminal 1: servidor local na porta 3000
node server.js

# terminal 2: túnel HTTPS para a porta 3000
ngrok http 3000
# copie a URL https://....ngrok-free.app e use abaixo

curl -X PUT "https://api.zapzapapi.com/api/v1/instances/$INSTANCE_ID/webhook" \
  -H "x-api-key: $ZAPZAP_API_KEY" \
  -H "x-api-secret: $ZAPZAP_API_SECRET" \
  -H "Content-Type: application/json" \
  -d '{"webhook_url":"https://SEU-SUBDOMINIO.ngrok-free.app/webhooks/zapzap","enabled":true,"events":["messages","connection"]}'

¿Por qué el webhook de n8n no recibe nada?

El nodo Webhook de n8n tiene dos URL: la de prueba (Test URL) y la de producción (Production URL). La de prueba solo escucha mientras haces clic en 'Listen for test event' en el editor, y queda activa por poco tiempo. La de producción solo funciona con el workflow activado. El error clásico es registrar la URL de prueba en ZapZap y después cerrar el editor: desde ahí no llega nada.

Para una automatización en uso, registra la Production URL y activa el workflow. Para desarrollar, registra la Test URL, haz clic en escuchar y manda un mensaje real al número. En n8n dentro de Docker o detrás de un proxy inverso, la dirección que muestra puede ser interna (localhost:5678). Define la variable de entorno WEBHOOK_URL de n8n con tu dominio HTTPS público; si no, muestra una URL que ZapZap no puede alcanzar. Revisa también que el proxy reenvíe el cuerpo y no bloquee el POST.

Si prefieres partir de un flujo listo, la página de integración con n8n trae tutorial y plantillas para importar, y las plantillas de n8n ya vienen con el disparador de webhook armado.

¿Está activado el evento correcto?

Los eventos del webhook vienen desactivados por defecto y tú eliges cuáles recibir. Si activaste solo connection, los mensajes nunca llegan. Para recibir mensajes, activa messages. Para saber si fue entregado o leído, activa messages_update. El catálogo completo está en configurar webhook.

Otro filtro que sorprende: excludeMessages. Si marcaste excluir mensajes propios, los enviados por ti no generan evento en el webhook, lo cual es deseable en bots pero confunde a quien busca el eco de su propio envío. Revisa ese campo en la respuesta de ver webhook.

Mi endpoint responde, pero las entregas aparecen con error. ¿Y ahora?

Lee la lista de entregas. Un status 4xx o 5xx significa que tu servidor respondió con error; revisa sus logs. Un timeout significa que la respuesta superó el límite de 10 segundos por intento. La causa casi siempre es trabajo pesado antes del res.send: llamada de IA, escritura lenta en la base de datos o envío de mensaje dentro de la solicitud. Responde 200 primero y procesa después, como en la guía de webhook en producción.

Las fallas se reenvían por una escalera de reintentos, y las fallas seguidas y permanentes pueden llevar a la desactivación del webhook. Si el webhook se desactivó, corrige la causa, ejecuta la prueba de webhook y configura la URL de nuevo. Un 401 o 403 de tu lado suele ser validación de firma hecha sobre el JSON ya parseado en lugar del cuerpo crudo, o un secreto desactualizado.

Si todo esto está bien y aun así no llega, habla con soporte llevando el delivery_id de una entrega, que identifica el evento en ambos lados.

Checklist rápido para cuando no llega nada

[ ] La instancia está conectada (status connected)

[ ] La URL es HTTPS, pública y responde en pocos segundos, sin pasar por login ni firewall

[ ] La configuración se guardó sin error y ver webhook muestra la URL y enabled en verdadero

[ ] Los eventos messages (y connection, si quieres avisos de caída) están en la lista

[ ] La prueba de webhook devuelve status 2xx y latencia baja

[ ] Las entregas recientes muestran intentos con status 2xx para mensajes reales

[ ] En n8n: Production URL con el workflow activo, o Test URL con el editor escuchando

[ ] Tu servidor no valida la firma sobre el JSON ya parseado

Si algún punto falla, corrígelo y repite la prueba antes de seguir. Los cambios de dominio, los certificados vencidos y las reglas nuevas de firewall son causas frecuentes de un webhook que funcionaba y dejó de hacerlo. En equipo, registra la URL del webhook y quién es responsable del certificado, porque un certificado vencido tumba el HTTPS y las entregas empiezan a fallar sin aviso de tu lado.

Resumen rápido

  • localhost y las IP privadas se rechazan. La URL del webhook tiene que ser HTTPS, pública y alcanzable.
  • Usa un túnel HTTPS para desarrollar y reconfigura la URL cada vez que el túnel cambie.
  • En n8n, la URL de prueba solo escucha durante el 'Listen for test event'. En producción usa la Production URL con el workflow activo.
  • Revisa los eventos activados (messages, messages_update, connection) y el filtro excludeMessages.
  • Diagnostica con el status de la instancia, ver webhook, las entregas recientes y los errores del webhook.

Lee también

Preguntas frecuentes

¿Por qué el webhook de WhatsApp no llega a mi localhost?

Porque el servidor de la API no ve tu máquina y, además, la configuración rechaza direcciones locales y privadas. Usa un túnel HTTPS (ngrok, cloudflared) o un servidor de pruebas con URL pública.

Guardé la URL y me dio error de URL inaccesible. ¿Qué hago?

Al guardar, la API hace una verificación de alcance con un límite de tiempo corto. Asegúrate de que el servidor esté arriba, con HTTPS válido, sin firewall bloqueando y respondiendo rápido a la solicitud.

¿El webhook de n8n funciona en modo de prueba?

Solo mientras haces clic en escuchar evento de prueba en el editor. Para uso continuo, activa el workflow y registra la Production URL en ZapZap. En Docker o detrás de un proxy, define WEBHOOK_URL con el dominio público.

Recibo el evento de conexión, pero no los mensajes. ¿Por qué?

Porque el evento messages no está activado en la configuración del webhook. Actualiza la lista de eventos con messages y, si quieres status de entrega y lectura, messages_update.

¿Cómo veo si ZapZap intentó entregar?

Con el endpoint de entregas recientes de la instancia: lista evento, status HTTP, latencia y número de intento. Los errores del webhook muestran el motivo de las fallas más recientes.

Prueba el webhook con un evento firmado

Crea la cuenta, verifica tu teléfono y recibe el crédito de bienvenida, sin depositar (uno por teléfono, sujeto a la campaña vigente). Conecta un número y ejecuta la prueba de webhook para ver la latencia de tu URL.