La API de GoHighLevel: los errores no documentados que te costarán horas

La API de GoHighLevel funciona, pero no funciona como dice el manual. Después de construir tres sistemas en producción contra ella (un servidor de integración con más de 140 endpoints mapeados, un motor de sincronización masiva y varias plataformas conectadas por webhooks), tengo una colección de comportamientos no documentados que costaron horas de debugging cada uno. Este artículo es esa colección: los errores que vas a encontrar, por qué ocurren y cómo se resuelven, para que tus horas las inviertas en construir y no en descubrir lo que aquí ya está escrito.

Respuesta rápida: los 7 quirks que más duelen

  • 403 sin razón aparente: Cloudflare bloquea peticiones sin User-Agent de navegador (Error 1010). Ningún mensaje te lo dice.
  • Header Version obligatorio: sin Version: 2021-07-28 muchos endpoints fallan; los de SaaS usan otra versión distinta.
  • El location cambia de nombre según el endpoint: location_id, locationId, altId+altType, o en el path. Cuatro convenciones, una API.
  • Paginación mixta: cursor en unos endpoints, offset en otros, páginas base-1 en otros.
  • 400 que debería ser 404: tocar un contacto borrado devuelve 400 con «Contact not found», no 404.
  • Rate limits reales: el 429 llega antes de lo que crees en cargas masivas; sin backoff no hay sincronización que sobreviva.
  • Fechas con margen: programar publicaciones sociales exige minutos de margen o el request falla.
SíntomaCausa realArreglo
403 Error 1010 intermitente o totalFalta User-Agent de navegadorEnviar un User-Agent tipo Chrome en TODA petición
Errores raros en endpoints que «existían»Falta header VersionVersion: 2021-07-28 siempre
«location required» con el location enviadoConvención equivocada para ese endpointTabla de convenciones (abajo)
400 «Contact not found»El contacto fue borrado en GHLTratarlo como 404: recrear o marcar
429 en cargas masivasRate limitBackoff creciente + reintentos acotados

La regla general: la API de GoHighLevel premia a quien encapsula sus rarezas en un cliente propio y castiga a quien llama endpoints a pelo.

El contexto: por qué la API es así

GoHighLevel creció rápido y su API lo delata: conviven generaciones distintas de endpoints con convenciones distintas, la documentación oficial va detrás del producto, y delante de todo hay un Cloudflare configurado con reglas de bot que no distinguen entre un atacante y tu integración legítima. Nada de esto la hace inutilizable; la hace traicionera para el que confía en la documentación. Los tres sistemas míos que la usan en producción comparten la misma lección: el costo real no está en construir la integración sino en descubrir estas reglas no escritas.

Un matiz de alcance: todo lo que sigue aplica a la API oficial v2 (services.leadconnectorhq.com) con Private Integration Token, que es la que llega con el plan Unlimited. Existe además una API interna no oficial con más poder y más riesgo; ese tema merece artículo propio y no es este.

¿Por qué falla la API de GoHighLevel si mi código está bien?

Las causas comunes no son tu código: la API de GoHighLevel exige un User-Agent de navegador (sin él, Cloudflare responde 403) y el header Version en cada petición, cambia el nombre del parámetro de location según el endpoint, y devuelve 400 en lugar de 404 para contactos borrados. Son comportamientos no documentados que se resuelven encapsulándolos en un cliente propio.

Los quirks, uno por uno

1. El 403 fantasma: Cloudflare y el User-Agent

El más desconcertante. Tu petición es válida, tu token es válido, y recibes un 403 con Error 1010 de Cloudflare. La causa: no enviaste User-Agent, o enviaste el de tu librería HTTP (python-urllib, axios). La protección anti-bot de GoHighLevel descarta esas firmas. El arreglo es humillante de simple: un User-Agent de navegador real en cada petición. En mis clientes HTTP va hardcodeado y con un comentario en mayúsculas para que nadie lo «limpie» en un refactor: quitarlo tumba la integración completa.

2. El header Version que nadie olvida dos veces

Toda petición a la API v2 necesita Version: 2021-07-28. Sin él, el comportamiento varía entre error explícito y respuesta rara según el endpoint, que es lo peor de ambos mundos. Y el detalle fino: los endpoints de SaaS usan una versión diferente (2021-04-15). Dos constantes en tu cliente, elegidas según el grupo de endpoints, y problema resuelto para siempre.

3. Un location, cuatro nombres

La subcuenta se identifica distinto según la generación del endpoint:

  • locationId (camelCase): la mayoría de endpoints modernos.
  • location_id (snake_case): la búsqueda de oportunidades, entre otros.
  • altId + altType=location: pagos, facturas y transacciones.
  • En el path: el social planner (/social-media-posting/{locationId}/...).

El error típico es «location required» cuando estás seguro de haberlo enviado: lo enviaste con la convención de otro endpoint. Mi solución de arquitectura: el cliente HTTP recibe siempre el location una sola vez y cada método interno sabe con qué nombre pasarlo. El que llama nunca decide la convención. Cero errores de este tipo desde entonces.

4. Paginación: tres modelos conviviendo

Cursor en unos endpoints, offset/limit en otros, número de página base-1 en otros, y casos donde skip y limit deben ir como strings numéricos o el endpoint protesta. No hay regla general: hay que leer la respuesta de cada endpoint y encapsular su modelo. Si tu capa de paginación asume un solo modelo, la sincronización se detiene silenciosamente a mitad de tabla, que es el peor tipo de error: el que no avisa.

5. El 400 que es un 404 disfrazado

Actualizas un contacto que alguien borró desde la interfaz y recibes 400 Bad Request con «Contact not found» en el cuerpo. Tu manejador de errores lo clasifica como petición malformada, reintenta, vuelve a fallar, y el registro queda atascado. En sincronizaciones masivas este caso es cotidiano: los contactos se borran a mano constantemente. El tratamiento correcto: detectar ese 400 concreto por su mensaje, tratarlo como 404, y decidir política (recrear el contacto si tu base externa es la fuente de verdad, o marcarlo como borrado si no). Mi motor de sincronización recrea; el detalle de esa arquitectura está en la guía de integración con capas externas.

6. Rate limits: el 429 llega antes de lo que planeaste

En operaciones sueltas nunca lo ves; en cargas masivas es el protagonista. Los números que sobreviven en mis sistemas: concurrencia moderada (8 operaciones paralelas), lotes con pausas breves, 2 o 3 reintentos por llamada con backoff creciente (del orden de 1,5 segundos multiplicado por el número de intento), timeout generoso de 40 segundos, y distinción estricta entre errores reintentables (429, 500, 502, 503, timeout) y permanentes (el resto). Con eso, una carga de miles de contactos fluye en minutos; sin eso, se estrella a los pocos cientos.

7. Fechas, márgenes y borrados suaves

Miscelánea que cuesta una tarde cada una: programar una publicación social exige que la fecha esté varios minutos en el futuro (el margen práctico ronda los 5 o 6) o el request falla; el borrado de publicaciones sociales es soft-delete (desaparece de la interfaz, no necesariamente de las respuestas de la API); y sacar a un contacto de un workflow donde ya no está devuelve 404, que conviene tratar como éxito y no como error, porque el estado final es el que querías.

El patrón que resuelve todo esto de una vez

Ninguno de estos quirks es grave por separado; el costo está en descubrirlos uno a uno en producción. La defensa estructural es siempre la misma y vale para cualquier lenguaje:

  • Un cliente HTTP propio que encapsula User-Agent, Version, convención de location por endpoint y paginación. Nadie en tu código llama a la API directamente.
  • Errores tipados: cada respuesta anómala se clasifica (reintentable, permanente, el 400-que-es-404) y la política vive en un solo lugar.
  • Nunca reenviar el cuerpo crudo de los errores de GHL hacia tus logs públicos o tu frontend: puede contener fragmentos sensibles. Sanitiza antes de registrar.
  • Un archivo de quirks en tu repositorio: cada rareza nueva que descubras, documentada con fecha y endpoint. Es el documento más rentable de toda la integración.

Esa inversión (un día de trabajo la primera vez) es la diferencia entre integraciones que se mantienen solas y las que despiertan a alguien cada semana. Es el mismo principio de estructurar el sistema para que sea mantenible, aplicado a la capa de API.

Preguntas frecuentes

¿Por qué recibo 403 de Cloudflare al llamar a la API de GoHighLevel?

Casi siempre por el User-Agent: la protección anti-bot descarta las firmas de librerías HTTP. Envía un User-Agent de navegador real en todas las peticiones. Si persiste, revisa que el token sea válido y que uses el dominio correcto de la API v2.

¿Qué header Version debo usar?

Version: 2021-07-28 para la API v2 general. Los endpoints de SaaS usan 2021-04-15. Defínelos como constantes en tu cliente y aplícalos según el grupo de endpoints; no los omitas nunca.

¿Cómo envío el location correctamente?

Depende del endpoint: locationId en la mayoría, location_id en búsqueda de oportunidades, altId con altType=location en pagos y facturas, y dentro del path en el social planner. Encapsula la convención en tu cliente para no decidirla en cada llamada.

¿La API de GoHighLevel tiene rate limits documentados?

Los límites prácticos se descubren operando: en cargas masivas el 429 aparece con concurrencias moderadas. La receta que funciona: pocas operaciones paralelas, backoff creciente ante 429, reintentos acotados y distinción entre errores reintentables y permanentes.

¿Estos comportamientos pueden cambiar?

Sí, y cambian sin aviso: la plataforma evoluciona semanalmente. Por eso el patrón importa más que la lista: cliente propio, errores tipados y quirks documentados absorben los cambios; el código que llama endpoints a pelo se rompe con cada uno. Esta página se actualiza cuando verifico cambios en producción.


Todo lo descrito está verificado en sistemas propios en producción contra la API v2, a julio de 2026. Si tu integración con GoHighLevel está en ese punto donde cada semana aparece un error nuevo, este es exactamente el tipo de arquitectura que implemento.

La lección detrás de la lista

Las APIs de plataformas jóvenes que crecen rápido son así: potentes, inconsistentes y poco documentadas en los bordes. Puedes enfadarte con eso o diseñar para eso. Los sistemas míos que llevan meses sincronizando sin intervención no lo lograron porque la API mejorara: lo lograron porque cada rareza descubierta se convirtió en código que la absorbe y en una línea de documentación que nadie más tendrá que pagar con sus horas. Esa es la diferencia entre integrar y sobrevivir integrando.

Imagen de Alexander González

Alexander González

Es Arquitecto de Sistemas CRM y Especialista en GoHighLevel. Fundador de Alex González GO y creador de Marketing Nativo. Trabaja desde el diagnóstico B2B y la gobernanza de datos antes de automatizar, bajo la firme premisa de que la tecnología debe sostener y escalar las operaciones, no reemplazarlas.

Más información - Whatsapp

Últimos posts

Transparencia: algunos enlaces de este sitio son de afiliado. Si contratas a través de ellos, Marketing Nativo recibe una comisión sin costo adicional para ti; es parte de cómo se financia este contenido. Marketing Nativo es un sitio independiente y no está afiliado oficialmente a HighLevel Inc. GoHighLevel y HighLevel son marcas de sus respectivos propietarios.