Integración PIM-VTEX con Node.js: sincronización de catálogo, precios y stock en tiempo real
Un caso técnico completo de integración entre un PIM y VTEX: arquitectura del conector, manejo de webhooks, sincronización incremental y control de errores.
Una integración entre un PIM y VTEX está bien diseñada cuando puede mantener sincronizados productos, variantes, categorías, atributos y assets sin reconstruir el catálogo completo en cada ejecución, conservar la correspondencia entre los identificadores de ambos sistemas y recuperarse de errores sin perder el estado del proceso.
Pero hay una aclaración importante desde el comienzo: aunque hablemos de una integración PIM-VTEX que involucra catálogo, precio y stock, eso no significa que esos tres tipos de información tengan que nacer en el PIM.
En una arquitectura habitual, el PIM gobierna la información relativamente estable y enriquecida del producto: nombres, descripciones, categorías, atributos, variantes, especificaciones e imágenes. Precio y stock son datos transaccionales, mucho más dinámicos, que normalmente provienen de un ERP, OMS, WMS u otro sistema operativo.
VTEX también refleja esta separación a nivel técnico: el catálogo, los precios y el inventario se administran mediante servicios y APIs diferentes.
Por eso, cuando desarrollo este tipo de integraciones con Node.js, prefiero no pensar en un único “conector PIM-VTEX”, sino en varios flujos coordinados que terminan convergiendo sobre la misma experiencia de producto.
Tiempo real no significa enviar toda la información por el mismo camino y a la misma velocidad. Significa que cada dato se actualiza con la frecuencia que necesita y desde el sistema que tiene autoridad sobre él.
¿Qué significa realmente integrar un catálogo PIM con VTEX?
Desde el PIM podemos ver un producto como una estructura relativamente compacta: un producto padre, sus variantes, una categoría, determinados atributos, imágenes y relaciones.
Cuando esa información llega a VTEX, tiene que adaptarse a otro modelo.
VTEX diferencia entre producto y SKU. El producto reúne la información común, mientras que el SKU representa una variante concreta que puede comercializarse. A esto se agregan categorías, marcas, especificaciones, imágenes y otras entidades que forman parte del catálogo.
Eso modifica la lógica del integrador.
No alcanza con obtener un objeto desde el PIM, transformarlo y hacer un POST. Antes necesitamos saber si existen las entidades de las que ese producto depende, qué ProductId le corresponde en VTEX, cuáles son los SkuId de sus variantes y cómo se relacionan las especificaciones.
Dicho de otra forma: el payload es la parte visible de la integración; el verdadero problema es conservar el estado y las relaciones entre dos modelos de datos diferentes.
¿Cómo conviene estructurar un conector PIM-VTEX con Node.js?
Una integración puede empezar siendo un script pequeño y crecer bastante rápido.
Al principio parece razonable poner todo en el mismo proceso: consultar el PIM, transformar el producto, llamar a VTEX, capturar errores y escribir logs. El problema aparece cuando incorporamos variantes, imágenes, precios, inventario, webhooks, reintentos y diferentes frecuencias de sincronización.
Por eso intento separar responsabilidades desde el diseño.
Una arquitectura puede dividirse en componentes como estos:
- cliente de la API del PIM;
- capa de validación y mapping;
- servicio de resolución de identificadores;
- cliente de VTEX Catalog;
- clientes independientes para Pricing y Logistics cuando corresponda;
- cola de trabajos;
- persistencia de estado y checkpoints;
- logging, métricas y alertas;
- proceso de reconciliación.
El circuito de catálogo puede representarse así:
PIM → extracción → validación → mapping → cola → VTEX Catalog → reconciliación
Mientras que precio y stock podrían seguir otra ruta:
ERP / OMS / WMS → transformación → cola → VTEX Pricing / Logistics
Separar estos flujos no es solamente una cuestión de orden del código. Permite que una falla en precio no bloquee la actualización de una descripción y que un problema de inventario no obligue a reconstruir productos y variantes.
Ese desacoplamiento se vuelve especialmente importante cuando el integrador empieza a funcionar como una pieza permanente del ecosistema y deja de ser un script que alguien ejecuta manualmente.
¿En qué orden hay que sincronizar las entidades de VTEX?
Otra dificultad aparece porque las entidades no son independientes.
Una variante necesita estar asociada a un producto. Un producto puede depender de una categoría existente. Las especificaciones también tienen su propia configuración. Las imágenes necesitan asociarse a las entidades correctas.
Por eso, una sincronización suele respetar una secuencia conceptual similar a:
categorías → especificaciones → producto → SKU → atributos → imágenes → publicación
El orden concreto puede variar según el alcance del proyecto, pero la regla es la misma: no conviene tratar cada request como una operación aislada cuando las entidades tienen dependencias entre sí.
Esto también modifica el manejo de errores. Si no pudimos crear un producto, intentar inmediatamente crear sus SKUs solo genera nuevos errores que en realidad tienen la misma causa.
Un integrador debería conocer esas dependencias y poder bloquear únicamente la rama afectada.
Un error de SKU puede ser un error del SKU. Pero también puede ser la consecuencia de que el producto del que depende nunca llegó a crearse. Una integración robusta distingue entre ambas situaciones.
IDs del PIM e IDs de VTEX: por qué hay que conservar el mapping
Supongamos que el PIM identifica un producto y una variante de esta manera:
{
"productId": "SHIRT-100",
"variantId": "SHIRT-100-BLACK-M",
"sku": "100-BLK-M"
}
Después de crear esas entidades en VTEX, podemos obtener otros identificadores:
{
"pimProductId": "SHIRT-100",
"pimVariantId": "SHIRT-100-BLACK-M",
"vtexProductId": 247,
"vtexSkuId": 891,
"refId": "100-BLK-M",
"lastSyncAt": "2026-08-27T19:30:00Z"
}
Guardar explícitamente esa correspondencia vuelve mucho más predecibles las siguientes actualizaciones.
Si mañana cambia la descripción de SHIRT-100, quiero poder consultar mi tabla de mapping y saber inmediatamente qué ProductId actualizar. Si cambia la variante SHIRT-100-BLACK-M, quiero conocer su SkuId sin volver a recorrer o intentar descubrir el catálogo.
Una buena integración no debería reconstruir la relación entre sistemas en cada ejecución. Debería conservarla y poder auditarla.
Los identificadores externos o referencias de negocio siguen siendo útiles, pero no reemplazan necesariamente los IDs internos que cada plataforma asigna a sus entidades. La capa de mapping es la que permite convivir con ambas cosas.
¿Cómo hacer una sincronización incremental sin reenviar todo el catálogo?
Si administramos 20.000 productos y desde la última ejecución cambiaron 30, no tiene sentido volver a procesar 20.000.
Sin embargo, muchos integradores empiezan precisamente así: un cron obtiene el catálogo completo, ejecuta transformaciones y vuelve a enviarlo periódicamente.
Puede funcionar mientras el catálogo es pequeño. Cuando aparecen miles de productos, variantes, imágenes y distintas APIs, el costo empieza a crecer innecesariamente.
Por eso prefiero trabajar con deltas, siempre que el sistema de origen permita identificarlos.
El proceso puede guardar un estado como este:
{
lastSuccessfulSync: "2026-08-27T20:00:00Z",
cursor: "...",
processed: 184,
failed: 3
}
La siguiente ejecución consulta únicamente los productos creados o modificados a partir de ese punto.
Pero hay una condición importante: el checkpoint no debería avanzar solamente porque comenzamos un lote. Tiene que representar el último estado que realmente podemos considerar confirmado.
Si el proceso falla a mitad de camino y ya actualizamos el checkpoint como si todo hubiera terminado correctamente, podemos perder cambios.
La sincronización incremental reduce volumen y permite aumentar la frecuencia de actualización, pero exige administrar el estado con más cuidado.
¿Webhooks o polling para acercarnos al tiempo real?
Los webhooks son especialmente útiles cuando queremos reaccionar rápido ante cambios.
Cuando un producto cambia, el sistema origen puede enviar un evento a nuestro integrador y evitar que tengamos que consultar permanentemente si ocurrió algo.
Pero me gusta hacer una distinción: el webhook debería indicar que hubo un cambio, no necesariamente transportar toda la verdad definitiva del producto.
Por eso prefiero un flujo como este:
cambio → webhook → validación → cola → consulta del producto → transformación → VTEX
El endpoint que recibe el webhook hace poco trabajo. Valida el evento, comprueba que no sea duplicado, lo registra, lo encola y responde.
Por ejemplo:
app.post("/webhooks/product", async (req, res) => {
const event = req.body;
await queue.add("sync-product", {
productId: event.productId,
eventId: event.id
});
return res.sendStatus(202);
});
La sincronización real se ejecuta después desde un worker.
Esto tiene varias ventajas: podemos controlar concurrencia, reintentar un trabajo, deduplicar eventos y responder al webhook rápidamente sin depender de cuánto tarde VTEX en procesar todas las operaciones necesarias.
Pero tampoco confiaría toda la consistencia del catálogo únicamente a eventos.
Mi patrón preferido es:
webhook para velocidad + sincronización incremental para recuperación + reconciliación periódica para control.
Si un webhook se pierde, el proceso incremental debería encontrar el cambio. Y si aparece una diferencia que ninguno de los dos procesos detectó, la reconciliación debería hacerla visible.
Catálogo, precio y stock: tres datos con ritmos diferentes
Ésta es probablemente la distinción más importante de toda la arquitectura.
Una descripción comercial puede cambiar una vez cada varios meses. El precio puede cambiar varias veces en un día. El stock puede variar después de cada venta o movimiento de depósito.
No tiene sentido aplicar la misma frecuencia de actualización a los tres.
Una arquitectura posible sería:
| Información | Sistema de origen habitual | Destino en VTEX | Cadencia |
|---|---|---|---|
| Nombre, descripción y atributos | PIM | Catalog | Incremental |
| Categorías y variantes | PIM | Catalog | Incremental |
| Imágenes y assets | PIM / DAM | Catalog | Incremental |
| Precio | ERP / sistema comercial | Pricing | Alta frecuencia o eventos |
| Stock | ERP / WMS / OMS | Logistics | Tiempo real o alta frecuencia |
Esto también ayuda a no convertir al PIM en un sistema que no necesita ser.
El PIM centraliza, estructura, enriquece y distribuye información de producto. El precio operativo y la cantidad disponible en un depósito pertenecen normalmente a sistemas transaccionales.
Que catálogo, precio y stock terminen juntos en una página de producto no significa que deban nacer en el mismo sistema ni viajar por la misma integración.
¿Cómo manejar errores sin detener todo el catálogo?
Imaginemos un lote de cien productos.
Noventa y ocho se procesan correctamente. Uno tiene una categoría inválida. Otro recibe un error temporal cuando intentamos actualizarlo en VTEX.
No quiero que el resultado final sea solamente:
FAILED
Necesito saber qué entidad falló, qué operación intentábamos ejecutar, si el error es recuperable y qué otros procesos pueden continuar.
Por eso suelo distinguir al menos tres tipos de error.
Los errores técnicos transitorios incluyen timeouts, indisponibilidades momentáneas o limitaciones temporales de la API. Son buenos candidatos para reintentos controlados.
Los errores de datos aparecen cuando el payload no cumple las reglas necesarias: un identificador falta, el mapping es inválido o un valor no corresponde a la entidad esperada. Repetir el request no suele resolver nada.
Los errores de dependencia aparecen cuando una entidad no puede procesarse porque otra anterior todavía no existe. Por ejemplo, intentar crear un SKU cuyo producto no pudo crearse.
Esta clasificación ayuda a evitar un error muy habitual: utilizar el mismo retry para cualquier excepción.
Reintentar automáticamente un timeout puede ser correcto. Reintentar cinco veces un producto con datos inválidos solamente produce cinco errores iguales.
Colas y workers: desacoplar los eventos de la escritura en VTEX
Cuando empiezan a crecer el volumen y la cantidad de flujos, una cola puede simplificar bastante el diseño.
El productor recibe el evento y crea un trabajo:
await queue.add("sync-vtex-product", {
correlationId,
productId,
eventId
});
Los workers procesan después esos trabajos con una concurrencia controlada.
También podemos separar los circuitos:
catalog-productscatalog-assetspricinginventory
De esta manera, una degradación temporal de Pricing no tiene por qué detener Catalog.
La cola también permite implementar retry con backoff, limitar la cantidad de requests simultáneos y enviar las operaciones que agotaron todos sus intentos a una dead-letter queue o a un estado de revisión.
La cola no elimina los errores. Lo que hace es convertir esos errores en estados administrables en lugar de excepciones perdidas dentro de un proceso.
Reconciliación: ¿VTEX quedó realmente igual que el PIM?
Sincronizar y reconciliar son dos operaciones distintas.
Sincronizar responde: “¿pude enviar este dato?”.
Reconciliar responde una pregunta más exigente: “¿el sistema destino terminó realmente en el estado que esperaba?”
Podemos haber enviado cien productos y haber recibido respuestas satisfactorias, pero eso no significa automáticamente que las relaciones, variantes o estados finales sean los correctos.
Dependiendo del proyecto, podemos comparar:
- producto PIM ↔
ProductIdVTEX; - variante PIM ↔
SkuIdVTEX; - categoría esperada ↔ categoría publicada;
- cantidad de variantes esperadas ↔ cantidad existente;
- estado activo o publicado;
- timestamp o versión de la última sincronización.
Un proceso puede terminar sin lanzar ninguna excepción y aun así dejar una inconsistencia.
Sincronización y reconciliación no son sinónimos. La primera mueve información; la segunda comprueba que el resultado final sea coherente.
Un caso real de integración PIM-VTEX con Node.js
En CRITERIA trabajamos con una operación multicanal en la que el PIM tenía que alimentar un ecosistema bastante más grande que una conexión directa entre dos plataformas.
Dentro de ese proyecto desarrollamos una serie de scripts JavaScript ejecutados sobre Node.js y coordinados mediante un orquestador para conectar el PIM con VTEX.
La integración debía crear y actualizar diferentes entidades del catálogo: categorías, atributos, assets, productos y variantes.
Eso obligaba a trabajar con mappings, secuencias de creación y transformaciones específicas entre los modelos de ambas plataformas. No era una exportación plana de productos, sino un proceso donde cada entidad tenía dependencias y una función dentro de la publicación final.
La experiencia confirma algo que aparece una y otra vez en este tipo de proyectos: conseguir las credenciales de dos APIs es el comienzo de la integración, no su diseño.
Hay que definir quién gobierna cada dato, cómo se relacionan los identificadores, qué cambios se procesan, cómo se recupera una operación y cómo comprobamos después que el destino quedó correctamente actualizado.
Checklist antes de poner una integración PIM-VTEX en producción
Antes del go-live, revisaría al menos estos puntos:
- Está definido qué sistema gobierna catálogo, precio y stock.
- Existe una correspondencia persistente entre IDs del PIM y IDs de VTEX.
- El orden de creación de las entidades está controlado.
- Los mappings fueron probados con productos simples y productos con variantes.
- La integración utiliza deltas cuando el sistema origen lo permite.
- Los webhooks tienen mecanismos de deduplicación.
- El webhook encola el trabajo y no ejecuta todo el proceso antes de responder.
- Hay límites de concurrencia.
- Los reintentos distinguen errores transitorios de errores de datos.
- Existen checkpoints persistentes.
- Un problema de Pricing no obliga a reconstruir Catalog.
- Un problema de inventario puede aislarse del contenido comercial.
- Los logs utilizan identificadores de correlación.
- Existen métricas sobre operaciones, errores, retries y tiempos de respuesta.
- Hay un proceso de reconciliación.
- Se probaron deliberadamente fallos parciales y recuperación, no solamente el camino feliz.
La función de este checklist no es prometer que nada va a fallar. Es conseguir que, cuando algo falle, sepamos qué pasó y qué tenemos que recuperar.
¿Cuándo está realmente bien diseñada una integración PIM-VTEX?
Para mí, una integración PIM-VTEX está bien diseñada cuando deja de depender de que todos los sistemas estén disponibles y todos los datos sean perfectos.
El camino ideal —llega el producto, transformamos, VTEX responde y terminamos— es solamente uno de los escenarios posibles.
La arquitectura también tiene que responder cuando el mismo webhook llega dos veces, una categoría todavía no existe, una imagen falla, un lote queda interrumpido o un SKU aparece en VTEX con un estado distinto del que esperábamos.
Ahí es donde Node.js deja de ser simplemente la tecnología con la que hacemos requests HTTP. Pasa a funcionar como una capa de integración y orquestación capaz de mantener coherencia entre sistemas con modelos, autoridades y velocidades diferentes.
En una arquitectura multicanal, trabajar “en tiempo real” no significa mover todo más rápido. Significa entender que una modificación de descripción, un cambio de precio y una unidad menos de stock son eventos diferentes, con orígenes, frecuencias y riesgos distintos. Cuando el integrador respeta esas diferencias y además puede detectar, aislar y recuperar errores, VTEX deja de ser el destino de una serie de scripts y pasa a formar parte de un flujo de información de producto realmente gobernado.
