Sincronización masiva con la API de GoHighLevel: la arquitectura

Sincronizar cincuenta contactos con la API de GoHighLevel es un tutorial. Sincronizar cincuenta mil es un proyecto de ingeniería, y la diferencia no está en el bucle: está en todo lo que el bucle ingenuo no contempla: los límites de peticiones que convierten horas en la unidad de medida, los timeouts de las funciones serverless que matan el proceso a la mitad, las corridas dobles que duplican datos, y los errores intermitentes que a volumen dejan de ser excepción para volverse estadística. Este artículo documenta la arquitectura de una sincronización masiva real en producción, con sus números: unos 8 contactos por segundo sostenidos, en lotes de 400, con reanudación automática y sin duplicar jamás.

El contexto del patrón: una base externa (el CRM de origen, una migración, un sistema propio) debe volcarse o mantenerse espejada contra GoHighLevel. Lo que sigue vale para la carga inicial grande y para la sincronización periódica que la mantiene viva después.

Respuesta rápida

  • La aritmética primero: con los límites de la API (ráfagas de 100 peticiones por 10 segundos), el techo práctico ronda los 8-10 contactos por segundo: 50.000 contactos son horas de proceso, y el diseño debe asumirlo.
  • Lotes con estado: el trabajo se parte en lotes (400 funciona bien) y el progreso se guarda tras cada uno: cualquier muerte del proceso reanuda desde el último lote confirmado.
  • Auto-encadenamiento: en serverless, cada ejecución procesa su lote y se invoca a sí misma para el siguiente, esquivando los límites de tiempo de ejecución.
  • Idempotencia por upsert: cada contacto se escribe por identidad (email/teléfono vía upsert), no por inserción: repetir un lote no duplica nada.
  • Candado optimista: una marca de «corrida en curso» impide que dos sincronizaciones simultáneas se pisen.
  • Backoff tipado: el 429 espera y reintenta; el 400 registra y continúa; el 500 reintenta con espera creciente. Cada tipo de error tiene su política, no un try/catch genérico.
Problema a escalaSíntoma sin diseñoPieza que lo resuelve
Rate limitsLluvia de 429 y proceso bloqueadoThrottling a ritmo sostenible + backoff
Timeout serverlessProceso muerto al minuto N, sin rastroLotes + auto-encadenamiento
Corrida interrumpidaReempezar desde cero (y duplicar)Checkpoint por lote + upsert
Dos corridas a la vezCarreras y datos pisadosCandado optimista
Errores intermitentesUn contacto malo tumba el lote enteroPolítica por tipo de error

Cinco problemas, cinco piezas. Ninguna es exótica; la ingeniería está en tenerlas todas antes de que el volumen te las cobre.

¿Cómo sincronizar miles de contactos con la API de GoHighLevel?

Partiendo el trabajo en lotes con progreso guardado, escribiendo cada contacto por upsert (idempotente), respetando los límites de la API con un ritmo de unos 8 contactos por segundo, y encadenando ejecuciones serverless que se reanudan solas. Con candado contra corridas simultáneas y política de reintentos por tipo de error, 50.000 contactos se sincronizan en horas, sin duplicados.

La arquitectura, pieza por pieza

1. La aritmética que define todo lo demás

Los límites publicados de la API v2 (100 peticiones por ráfaga de 10 segundos, 200.000 diarias por subcuenta) fijan el techo teórico en 10 por segundo. En la práctica, entre latencias y márgenes de seguridad, el ritmo sostenible ronda los 8. Esa cifra convierte cualquier promesa de «migramos esta tarde» en matemática: 10.000 contactos ≈ 20 minutos; 50.000 ≈ 2 horas; 200.000 ≈ un día con presupuesto diario incluido. Diseñar sin esta aritmética es como planear un viaje sin saber que el coche tiene velocidad máxima: todo el plan hereda el error.

2. Lotes con checkpoint: la unidad de reanudación

El proceso nunca es «un bucle de 50.000»: son 125 lotes de 400, y tras cada lote se persiste el progreso (último procesado, contadores, errores) en la base de control. La consecuencia es la propiedad que separa producción de tutorial: el proceso puede morir en cualquier momento sin perder nada. Deploy a mitad de corrida, función expirada, red caída: la siguiente ejecución lee el checkpoint y continúa desde el lote siguiente, no desde cero. El tamaño de 400 no es sagrado: es el equilibrio que encontramos entre eficiencia de proceso y granularidad de reanudación, y cualquier valor entre 200 y 500 funciona si el checkpoint acompaña.

3. Auto-encadenamiento serverless

Las funciones serverless tienen límites de ejecución que una sincronización de horas revienta. El patrón que lo resuelve: cada invocación procesa UN lote (minutos, cómodamente dentro del límite) y, antes de terminar, se invoca a sí misma para el siguiente. La «corrida» deja de ser un proceso largo y se vuelve una cadena de procesos cortos, cada uno barato, reanudable y dentro de los límites de la plataforma. Sobre la misma base de Supabase que ya juega otros papeles en la arquitectura, las edge functions encadenadas hacen este trabajo sin infraestructura adicional.

4. Upsert: la idempotencia que perdona todo

La regla de oro de cualquier proceso reanudable: repetirlo no puede duplicar. La API de contactos ofrece upsert por identidad (email o teléfono), y usarlo en lugar de crear a ciegas convierte cada reprocesamiento en inofensivo: el lote que se procesó una vez y media por una interrupción produce el mismo resultado que procesado una vez. Sin esta pieza, cada una de las anteriores (checkpoints, reanudación) sería una fábrica de duplicados con buenos modales.

5. El candado y los errores con apellido

Dos piezas de disciplina cierran el sistema. El candado optimista: antes de arrancar, la corrida marca «en curso» en la base de control y verifica que nadie más lo esté; el cron que dispara la sincronización nocturna mientras la carga inicial sigue viva se encuentra la puerta cerrada y se va. Y la política por tipo de error: el 429 (límite) espera con backoff creciente y reintenta; el 400 (dato malo: un email inválido, uno de los quirks documentados) registra el contacto en la lista de fallidos y sigue, porque un registro corrupto no puede secuestrar a los 49.999 restantes; el 500 reintenta un par de veces y luego registra. Al final, el reporte de corrida dice exactamente qué entró, qué falló y por qué: sin ese reporte, «terminó» es una palabra sin contenido.

Cuándo NO montar esto

Para una migración única de pocos miles de contactos, la importación por CSV de la propia plataforma es la herramienta correcta: robusta, con mapeo de campos y sin una línea de código. Este patrón se justifica cuando la sincronización es RECURRENTE (el espejo debe mantenerse vivo) o cuando el volumen y las transformaciones superan lo que el CSV expresa. Y para el flujo inverso (respaldar GoHighLevel hacia fuera), el patrón hermano ya está documentado en la guía de respaldos.

Errores comunes

  • El bucle ingenuo: for contacto in lista: crear(contacto). Funciona en la demo de 50, muere en el minuto 3 de la corrida de 50.000, y deja mitad de trabajo sin saber cuál mitad.
  • Crear en lugar de upsert: toda interrupción más reintento produce duplicados, y deduplicar después cuesta más que el proyecto original.
  • Ignorar el presupuesto diario: 200.000 peticiones al día por subcuenta suenan infinitas hasta que la corrida grande compite con el resto de tus integraciones ese mismo día.
  • Reintentar el 400: el dato malo no mejora con insistencia; reintentar errores permanentes solo quema límite y tiempo. Clasifica antes de reintentar.
  • Sin reporte de fallidos: los 200 contactos que no entraron y nadie sabe cuáles son. La lista de fallidos con motivo es parte del entregable, no un lujo.

Preguntas frecuentes

¿Cuánto tarda de verdad una sincronización de 50.000 contactos?

A ritmo sostenible de unos 8 contactos por segundo, alrededor de 2 horas de proceso efectivo. Con validaciones, transformaciones y los márgenes del mundo real, planifica media jornada. Lo que no debería tardar es tu tiempo: bien montada, corre sola y reporta al terminar.

¿Esto necesita el plan Unlimited de GoHighLevel?

Sí: la escritura directa y masiva por API es exactamente el caso que requiere la API completa, disponible de Unlimited hacia arriba. Con Starter, la vía de importación CSV nativa cubre las migraciones únicas.

¿Qué pasa con los custom fields en una sincronización masiva?

Se mapean por identificador de campo y se validan antes de enviar: el custom field con formato inesperado es la causa número uno de errores 400 a volumen. La regla de producción: normalizar y tipar ANTES de tocar la API, nunca confiar en que el origen viene limpio.

¿Puedo mantener una sincronización continua en lugar de corridas?

Sí, y el patrón maduro combina ambas: los webhooks empujan cambios individuales en tiempo real, y una corrida periódica (nocturna o semanal) reconcilia el conjunto completo contra el origen, atrapando lo que los eventos perdieron. Es el mismo principio push más pull de toda integración crítica.

¿Qué base de control necesita el proceso?

Tres tablas humildes: corridas (estado, candado, contadores), checkpoints (progreso por lote) y fallidos (contacto, motivo, lote). Cualquier Postgres las sostiene; el valor no está en la infraestructura sino en que el proceso las use con disciplina.


Arquitectura verificada en una sincronización propia en producción moviendo decenas de miles de contactos contra la API v2, a julio de 2026. Si tienes una migración o un espejo de datos que ya te dio un susto, este es el tipo de sistema que construyo.

La idea de fondo

La sincronización masiva es el examen sorpresa de tu madurez de integración: revela si tus procesos asumen el mundo feliz o el mundo real. Las cinco piezas de este artículo (aritmética, lotes, encadenamiento, upsert, candado con errores tipados) son la misma decisión repetida: asumir que el proceso SE VA a interrumpir, que los datos SÍ vienen sucios y que los límites NO se negocian, y diseñar para que nada de eso importe. El bucle ingenuo apuesta a que todo saldrá bien. El sistema de producción garantiza que da igual si no.

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.