Todos los artículos

Gestores de canal y marketplaces: el problema de integración que nadie te cuenta

Publicado 10 oct 20254 min de lectura
  • Ingeniería
  • Lueira
Gestores de canal y marketplaces: el problema de integración que nadie te cuenta

Ideas clave

  • El trabajo real de un gestor de canal es absorber el ritmo de webhooks, los límites de polling y los modos de fallo de cada marketplace sin que se filtren en el calendario de una escuela.
  • Trata tu propio motor de disponibilidad como la única fuente de verdad; cada conexión con un marketplace debe ser una capa de sincronización, no un igual.
  • Los webhooks llegan duplicados, desordenados o no llegan nunca — cada reserva entrante necesita un ID externo estable para hacer dedupe, además de una política clara para cuando el doble booking sigue ocurriendo.

Cada post anterior de esta serie daba por sentado algo que ya no puedo dar por sentado: que controlamos todo el sistema. El post sobre el motor de reservas trataba de reservar una plaza sin competir contigo mismo. El post sobre disponibilidad en tiempo real trataba de mantener los números consistentes en cada pantalla que un cliente pudiera estar mirando. El post sobre multi-tenancy trataba de aislar escuelas que comparten infraestructura. Todo eso vive dentro de los límites propios de Lueira — nuestra base de datos, nuestra API, nuestras reglas.

Los gestores de canal no tienen ese lujo. Lueira permite que una escuela conecte sus actividades a marketplaces de actividades de terceros "de forma rápida y eficiente" — como dice literalmente la descripción de la función en la web — de modo que el inventario de una escuela de esquí aparezca a la venta en una plataforma externa, no solo en su propio storefront de Lueira. Esa frase es sencilla. Lo que implica por debajo, no lo es.

1. Lo que promete de verdad un gestor de canal

El discurso hacia una escuela es directo: conecta una vez, vende en todas partes. Tus cinco plazas de clase de esquí del martes por la mañana son las mismas cinco plazas, ya reserve un cliente a través de tu propia web o a través de un marketplace que agrega actividades de una docena de operadores del valle. Para que esa promesa se sostenga, Lueira tiene que hablar con la API de cada marketplace, traducir nuestro modelo interno de actividades, plazas y precios a la forma que espere ese marketplace, y mantener a ambos lados honestos sobre cuántas plazas quedan realmente. Ese es el 20% fácil de la funcionalidad — un adaptador por marketplace. El 80% difícil es lo que pasa después de la primera sincronización, en cada cambio a partir de entonces.

2. Disponibilidad que no controlas

El problema de disponibilidad en tiempo real que resolvimos antes daba por hecho una única fuente de verdad: nuestra propia base de datos, nuestras propias escrituras, nuestros propios locks. Un gestor de canal rompe esa suposición a propósito. Ahora, las fuentes de verdad que importan para la reserva de un cliente incluyen sistemas que no gestionamos en absoluto.

Cada marketplace es distinto. Algunos envían webhooks en el instante en que algo cambia en su lado; otros esperan que hagamos polling, limitado por sus rate limits. Unos actualizan casi al instante; otros encolan cambios durante picos de carga. Y cada uno falla de forma distinta: una API que sencillamente está caída durante una hora, una suscripción de webhook que deja de entregar en silencio, un marketplace que confirma una petición y luego nunca llega a aplicarla.

3. Gestionar el doble booking que sigue ocurriendo

Una reserva hecha en un marketplace externo tiene que reducir la disponibilidad en todos los demás sitios — el propio storefront de Lueira y cualquier otro marketplace conectado — prácticamente al instante. No podemos simplemente consultar nuestro propio estado en vivo, porque el estado que acaba de cambiar vive en los servidores de otra persona. Hay una ventana en la que nuestros números están desactualizados en todas partes excepto en el marketplace que acaba de vender la plaza.

func handleMarketplaceBooking(w http.ResponseWriter, r *http.Request) {
    var evt MarketplaceBookingEvent
    if err := json.NewDecoder(r.Body).Decode(&evt); err != nil {
        http.Error(w, "bad payload", http.StatusBadRequest)
        return
    }

    // Toda reserva de marketplace lleva un ID externo. Esa es nuestra
    // clave de dedupe — los webhooks pueden llegar duplicados, desordenados,
    // o después de que ya hayamos recogido la misma reserva vía polling.
    if existing, _ := store.FindByExternalRef(evt.MarketplaceID, evt.ExternalBookingID); existing != nil {
        w.WriteHeader(http.StatusOK) // ya procesado, confirmamos y seguimos
        return
    }

    slot, err := availability.Reserve(evt.ActivityID, evt.SlotID, evt.Spots)
    if err != nil {
        // Alguien más ya se quedó con la plaza. Este es el flujo de disculpa.
        notifyOversell(evt)
        w.WriteHeader(http.StatusConflict)
        return
    }

    store.RecordExternalBooking(evt.MarketplaceID, evt.ExternalBookingID, slot)
    channels.PushAvailabilityUpdate(evt.ActivityID, slot) // propaga a cada otro canal
    w.WriteHeader(http.StatusOK)
}

Cuando esa rama de conflicto salta de verdad, el cliente de alguien recibe un mensaje de disculpa, un reembolso y, si es posible, una plaza alternativa. No hemos encontrado la forma de hacer que esa rama sea imposible — solo formas de hacerla rara y de gestionarla con elegancia en lugar de en silencio.

4. Mantener la fuente de verdad en un solo sitio

La decisión de diseño que evita que esto se convierta en un caos es negarse a tratar los marketplaces externos como igualmente autoritativos. El propio motor de disponibilidad de Lueira sigue siendo la única fuente de verdad. Cada integración de canal es una capa de sincronización sobre él, no un igual.

Sobre eso necesitábamos además una capa de reconciliación, porque los webhooks no son un mecanismo de entrega fiable — llegan duplicados, desordenados o no llegan nunca. Cada notificación de reserva entrante necesita un ID externo estable con el que hacer dedupe, más trabajos de reconciliación periódicos que comparen nuestra visión con la del marketplace.

Hemos sido honestos con nosotros mismos en que esto no cierra la brecha del todo. Un doble booking sigue ocurriendo de vez en cuando. Lo que construimos no es una garantía de que no pueda pasar — es una política de qué pasa cuando pasa. Los gestores de canal son, debajo del lenguaje de marketing, un problema de sistemas distribuidos disfrazado de industria de viajes.