El webhook es el momento en que GoHighLevel deja de ser una isla: un contacto paga, un formulario entra, un workflow decide, y tu sistema externo se entera al instante. En los tutoriales, esto toma cinco minutos. En producción, la diferencia entre un webhook de tutorial y uno confiable son cuatro decisiones que casi nadie toma hasta que un pago duplicado o un endpoint abierto al mundo se las enseña: autenticación, idempotencia, normalización y respuesta rápida. Este artículo documenta las cuatro, desde sistemas reales que llevan meses recibiendo webhooks de GoHighLevel sin sustos.
Respuesta rápida
- Cómo se envían: desde un workflow de GoHighLevel con la acción de webhook, que hace POST a tu URL con los datos del contacto y del evento (los campos extra van con Custom Data).
- Autenticación: GoHighLevel no firma sus webhooks; la práctica de producción es un secreto compartido en un header que tu endpoint verifica antes de procesar nada.
- Idempotencia: asume entregas repetidas; procesa cada evento una sola vez usando una clave única (contacto + evento).
- Respuesta: responde rápido (2xx) y procesa después; el trabajo pesado nunca vive en el mismo request.
- Lo que nadie te dice: los custom fields llegan con formatos que hay que normalizar antes de tocar tu base.
| Decisión | Tutorial | Producción |
|---|---|---|
| Seguridad | URL abierta «que nadie conoce» | Secreto compartido verificado en header |
| Entregas repetidas | Se ignora el problema | Idempotencia por clave única |
| Datos del payload | Se usan tal cual llegan | Normalización antes de escribir |
| Procesamiento | Todo en el request | Responder ya, procesar aparte |
La URL secreta no es un plan de seguridad. Es la ausencia de uno.
El contexto: qué webhook estamos hablando
GoHighLevel tiene dos direcciones de webhook y conviene nombrarlas para no mezclarlas. Los salientes (los de este artículo): un workflow ejecuta la acción de webhook y GoHighLevel hace POST a tu sistema; es la vía estándar para reaccionar a eventos (pago recibido, formulario enviado, etiqueta añadida) desde fuera. Y los entrantes: tu sistema dispara un workflow de GoHighLevel llamando a su URL de inbound webhook. Los patrones de este artículo aplican a los primeros, aunque la idempotencia y la normalización sirven igual en ambas direcciones.
El receptor típico es una función serverless o un endpoint de tu backend. En mis implementaciones son funciones en el borde conectadas a una base Postgres, pero los cuatro patrones son agnósticos: valen para n8n, para un endpoint propio o para cualquier receptor que hable HTTP.
¿Cómo funcionan los webhooks de GoHighLevel?
Los webhooks de GoHighLevel se configuran como acción dentro de un workflow: cuando el flujo llega a ese paso, la plataforma envía un POST a la URL definida con los datos del contacto, y con Custom Data puedes añadir campos extra. Tu endpoint debe verificar un secreto compartido, responder rápido con 2xx y procesar el evento de forma idempotente.
Tiempos reales de implementación:
- Receptor básico seguro (secreto + log + respuesta rápida): media jornada.
- Con idempotencia y normalización de custom fields: 1 jornada.
- Patrón completo con cola de procesamiento y reintentos propios: 2 jornadas.
Las cuatro decisiones de producción
1. Autenticación: el secreto compartido
GoHighLevel no firma criptográficamente sus webhooks salientes, así que la verificación queda de tu lado. El patrón que uso en producción: un header propio (por ejemplo X-Webhook-Secret) con un valor largo y aleatorio, configurado en la acción del workflow, que el endpoint compara antes de leer una sola línea del payload. Si no coincide, 401 y silencio. Detalle de plataforma si tu receptor es una función serverless con autenticación JWT por defecto: hay que desactivarla para esa ruta concreta (GoHighLevel no va a enviarte un JWT) y dejar que el secreto haga el trabajo. Un endpoint sin esto es una puerta abierta a que cualquiera inserte «pagos» en tu sistema con un curl.
2. Idempotencia: el mismo evento llegará dos veces
Los reintentos existen, los workflows se reejecutan, los humanos duplican pasos al editar flujos. Tu receptor debe asumir que cada evento puede llegar más de una vez y producir el mismo resultado neto. La técnica es vieja y infalible: una clave única por evento (ID del contacto + tipo de evento + referencia externa cuando existe, como el ID de transacción en pagos) con restricción de unicidad en tu base. El duplicado no falla: se reconoce y se ignora. En mi sistema de reconciliación de pagos, esa clave es la diferencia entre un reporte confiable y clientes cobrados dos veces en el dashboard.
3. Normalización: los custom fields no son lo que parecen
El payload trae los campos estándar del contacto con nombres predecibles, y los custom fields con la forma en que tu subcuenta los definió: nombres con espacios y acentos, valores como strings aunque sean números, opciones de dropdown con el texto literal. El error clásico es escribir eso tal cual en tu base y descubrir tres semanas después que «Plan Premium», «plan premium» y «PLAN PREMIUM » son tres valores distintos. La capa de normalización (mapear cada custom field a tu columna, tipar valores, recortar espacios, unificar catálogos) va ANTES de cualquier escritura, y es donde vive la mitad del trabajo real de un webhook serio. El beneficio lateral: esa capa documenta implícitamente qué campos usa tu negocio de verdad, un inventario que después vale oro en cualquier migración o auditoría.
4. Responder ya, procesar después
El workflow de GoHighLevel espera tu respuesta; tu procesamiento (validar, escribir en varias tablas, disparar efectos) puede tomar segundos. El patrón sano: el endpoint valida el secreto, encola o registra el evento crudo, responde 200, y el procesamiento corre aparte (una cola de trabajos, una segunda función, un worker). Beneficio doble: el workflow nunca sufre timeouts por tu culpa, y un fallo de procesamiento se reintenta desde tu cola con el evento intacto, en lugar de perderse en el limbo entre plataformas. La implementación mínima de esta idea ni siquiera necesita infraestructura de colas: una tabla de eventos crudos con estado pendiente/procesado y un proceso que la recorre cada minuto cumple el patrón completo con una tarde de trabajo.
Cuándo NO usar webhooks
Dos casos. Para datos que puedes consultar cuando los necesitas (reportes, sincronizaciones periódicas), el polling programado contra la API es más simple y más robusto que mantener un receptor: los webhooks pagan su complejidad cuando la latencia importa. Y para efectos dentro de la propia plataforma (etiquetar, mover pipeline, enviar mensaje), el workflow nativo lo hace sin salir: sacar el evento para volver a meterlo es automatización por deporte, con costo de ejecución premium incluido en la salida.
Errores comunes
- Endpoint sin autenticación: cualquiera que descubra la URL puede fabricar eventos. Y las URLs se descubren.
- Procesar en el request: timeouts intermitentes del lado GoHighLevel que nadie sabe explicar.
- Confiar en una sola entrega: duplicados silenciosos en pagos y contadores que no cuadran.
- Escribir custom fields sin normalizar: tres versiones del mismo valor y reportes rotos semanas después.
- No registrar el payload crudo: sin el evento original guardado, cada bug de procesamiento es irreproducible.
- Olvidar el costo: la acción de webhook es ejecución premium; a volumen, el diseño de cuántos webhooks salen por lead es una línea de la factura.
Preguntas frecuentes
No hay firma criptográfica en los webhooks salientes de workflows: la seguridad queda del lado del receptor. El estándar práctico es el secreto compartido en un header verificado antes de procesar, con valor largo, aleatorio y rotable.
Los campos del contacto asociado al workflow y lo que añadas como Custom Data en la acción (valores de custom fields, datos del evento, referencias). La recomendación de producción: enviar lo mínimo identificable y consultar el resto por API si hace falta, porque los payloads grandes fallan más y se depuran peor.
Con un receptor de pruebas (un endpoint temporal que registra lo que llega) conectado a un workflow de prueba con un contacto de prueba. Ver el payload real de TU subcuenta, con TUS custom fields, vale más que cualquier documentación: los nombres y formatos exactos salen de ahí.
No diseñes asumiendo reintentos infinitos de la plataforma: el evento puede perderse. Por eso el patrón serio combina webhooks (latencia baja) con una sincronización periódica de respaldo por API que reconcilia lo que falte. Los webhooks avisan rápido; el polling garantiza completitud. Esa pareja (evento inmediato más reconciliación periódica) es el estándar de las integraciones que no pierden datos, en GoHighLevel y en cualquier plataforma.
Saliente si GoHighLevel debe avisarle a tu sistema (pago, formulario, evento de workflow). Entrante si tu sistema debe disparar un workflow de GoHighLevel. Las integraciones maduras suelen usar ambos, cada uno en su dirección, con los mismos principios de secreto e idempotencia.
Patrones verificados en sistemas propios en producción recibiendo webhooks de GoHighLevel, a julio de 2026. Si tu integración todavía es la versión de tutorial y ya mueve dinero real, ese endurecimiento es exactamente lo que implemento.
La regla que resume las cuatro
Un webhook de producción se diseña para el día malo: el evento duplicado, el atacante con curl, el campo con formato sorpresa, el pico de tráfico durante tu deploy. Los cuatro patrones de este artículo son la misma idea repetida: no confíes en que el camino feliz sea el único camino. El webhook de tutorial funciona en la demo. El de producción funciona en diciembre, a las 3 de la mañana, mientras duermes. Esa es toda la diferencia, y se construye en dos jornadas.





