# Métodos de Sincronización

## Introducción

La sincronización de eventos permite a menta tech conocer tu inventario para habilitar la reventa. Existen diferentes métodos para lograr esta sincronización, dependiendo de las capacidades técnicas de tu plataforma.

Independientemente del método elegido, la estructura de la información (cómo defines tickets y precios) es crítica. Consulta la guía de **[Estructura de Datos](/es/guides/infoStructure)** para entender cómo modelar tu inventario correctamente.

## Opciones de Integración

{% table highlight-first=true highlight-row=2 %}
| Opción | Descripción | Cuándo tiene sentido | Beneficios | Limitaciones |
|--------|-------------|----------------------|------------|--------------|
| Usando la API de menta tech (recomendado) | La plataforma envía peticiones de CREATE/UPDATE directamente a menta | Cuando la sincronización en tiempo real y la precisión son importantes | Actualizaciones en tiempo cercano a real, sin polling, opción más escalable | Requiere emitir actualizaciones salientes desde el backend |
| Endpoint de eventos expuesto por la plataforma | menta tech consulta periódicamente un endpoint de eventos de la plataforma de ticketing | Cuando ya existe un endpoint de eventos ó se prefiere un modelo basado en consultas (pull) | Adopción sencilla, la plataforma controla estructura y frecuencia | Los datos pueden quedar desactualizados, el polling suma carga y no es ideal para cambios frecuentes |
| Carga manual de eventos | Los eventos se crean de forma manual, sin usar APIs | Para pilotos o partners de bajo volumen | Sin desarrollo, salida a producción más rápida | No escalable, operación manual, mayor riesgo de datos desactualizados |
{% /table %}

{% conditionaltabs id="tabs-1765309889524" %}

{% tab label="API de menta tech" %}
## Envío vía API (Push)

Este es el método recomendado para integraciones robustas. Tu backend actúa como fuente de verdad y notifica a menta cada vez que hay cambios.

### Implementación

Debes enviar requests a nuestra API cada vez que se cree, actualice o cancele un evento.

```bash
POST /v1/events
```

El cuerpo del request (JSON) dependerá del modelo de datos que elijas (Estandar, Precio Simple o Avanzado). **Revisa la guía de [Estructura de Datos](/es/guides/infoStructure)** para ver los esquemas JSON requeridos.

Enlaces útiles:
- <a href='https://connect.mentatech.io/es/api/post-events' target="_blank">Crear evento (API Reference)</a>
- <a href='https://connect.mentatech.io/es/api/put-events' target="_blank">Actualizar evento (API Reference)</a>
{% /tab %}

{% tab label="Endpoint expuesto por tu plataforma" %}
## Endpoint Pull

Tu plataforma expone una URL pública (ej: `https://api.tuplataforma.com/menta-feed`) y menta la consulta periódicamente para buscar actualizaciones.

### Requisitos del Endpoint

El endpoint debe devolver un JSON con la lista de eventos activos (un array de objetos). La estructura de cada evento debe incluir detalles de ubicación, productores y shows.

Dentro de cada show, la estructura de `ticketOptions` debe seguir las definiciones de la guía de **[Estructura de Datos](/es/guides/infoStructure)**.

### Estructura JSON requerida

A continuación, un ejemplo de cómo debe verse el array de eventos devuelto por tu endpoint:

{% columns gap="2rem" align="start" %}

{% column width="1" valign="top" %}
**Campos clave:**
- **Array Raíz**: La respuesta debe ser una lista `[...]`.
- **Evento**: `title`, `description`, `externalReferenceId`.
- **Location**: `city`, `venueName`, `address`.
- **Producers**: Información de contacto.
- **Shows**: Array de funciones.
  - **status**: Estado del show (`ON_SALE`, `CANCELLED`, `RESCHEDULED`, `ANNOUNCED`, `HIDDEN`, `PRIVATE`).
  - **dates**: Objeto de fechas del ciclo de vida (`startsAt`, `salesStartAt`, `salesEndAt`, `publicAt`).
  - **tags**: Array de strings en formato `key:value`.
  - **ticketOptions**: Array crítico para la reventa (categorías de acceso). Cada ítem incluye `price` (precio de la categoría **excluyendo comisiones y cargos**) y, opcionalmente, `area` (agrupador de zona — varios ticketOptions pueden compartir el mismo `area`).
  - **priceTypes** *(opcional)*: Tipos de precio disponibles para la venta (ej: Adult, Special Discount, Preventa).
  - **combinations** *(obligatorio si hay `priceTypes`)*: Combinaciones válidas de `ticketOption` + `priceType` que realmente existen en tu catálogo. Cada combinación lleva su propio `price` (también excluyendo comisiones y cargos) y, opcionalmente, un `description`.
{% /column %}

{% column width="1" valign="top" %}
```json
[
  {
    "title": "Concierto Ejemplo",
    "description": "Descripción del evento de ejemplo.",
    "externalReferenceId": "evt_example_001",
    "shows": [
        {
            "title": "Concierto Ejemplo - Función Principal",
            "primarySalesUrl": "https://tuplataforma.com/evento/concierto-ejemplo/show/001",
            "images": [
                {
                    "url": "https://ejemplo.com/imagenes/evento-principal.jpg",
                    "kind": "main"
                }
            ],
            "showId": "show_example_001",
            "status": "ON_SALE",
            "dates": {
                "startsAt": "2025-12-15T20:00:00.000-03:00",
                "salesStartAt": "2025-10-01T10:00:00.000-03:00",
                "salesEndAt": "2025-12-15T18:00:00.000-03:00",
                "publicAt": "2025-09-15T00:00:00.000-03:00"
            },
            "tags": ["genre:rock", "tour:2025"],
            "ticketOptions": [
                {
                    "title": "General",
                    "ticketId": "GEN_001",
                    "description": "Acceso general al evento",
                    "currency": "USD",
                    "price": 100,
                    "area": "Campo"
                },
                {
                    "title": "VIP",
                    "ticketId": "VIP_001",
                    "description": "Acceso VIP con beneficios exclusivos",
                    "currency": "USD",
                    "price": 250,
                    "area": "Platea"
                }
            ],
            "priceTypes": [
                {
                    "priceTypeId": "adult",
                    "title": "Adult"
                },
                {
                    "priceTypeId": "special-discount",
                    "title": "Special Discount"
                }
            ],
            "combinations": [
                {
                    "ticketOptionId": "GEN_001",
                    "priceTypeId": "adult",
                    "price": 100,
                    "description": "General – Adult"
                },
                {
                    "ticketOptionId": "GEN_001",
                    "priceTypeId": "special-discount",
                    "price": 70
                },
                {
                    "ticketOptionId": "VIP_001",
                    "priceTypeId": "adult",
                    "price": 250
                }
            ]
        }
    ],
    "location": {
        "city": "Buenos Aires",
        "state": "Buenos Aires",
        "venueName": "Estadio Ejemplo",
        "address": "Av. Ejemplo 1234",
        "country": "Argentina"
    },
    "producers": [
        {
            "name": "Productor Ejemplo",
            "emails": [
                "contacto@productor-ejemplo.com"
            ],
            "producerId": "prod_001"
        }
    ]
  }
]
```
{% /column %}
{% /columns %}

{% callout type="warning" title="priceTypes y combinations" %}
Los `priceTypes` son **opcionales**: si tu catálogo no tiene variaciones de precio dentro de una misma categoría de acceso, podés omitir este array y trabajar solo con `ticketOptions` (modelo Estandar).

Ahora bien, **si enviás `priceTypes`, estás obligado a enviar `combinations`**. menta tech no genera combinaciones automáticamente: solo existirán las combinaciones que definas explícitamente en ese array. Si una combinación `ticketOption` + `priceType` no aparece en `combinations`, no existirá en menta aunque ambas dimensiones estén declaradas.

Revisá la guía de **[Estructura de Datos](/es/guides/infoStructure)** para entender cuándo conviene cada modelo.
{% /callout %}

{% callout type="info" title="Precios sin comisiones ni cargos" %}
Tanto `ticketOption.price` como `combination.price` deben expresarse **excluyendo comisiones y cargos**: es el precio base de la categoría (o de la combinación) tal como lo cobrás vos, sin fees de servicio ni impuestos adicionales que puedas sumar en el checkout primario.

Cuando hay `combinations`, el precio de cada combinación **prevalece** sobre el `price` declarado en la ticketOption asociada; la ticketOption queda como referencia de la categoría.
{% /callout %}

{% callout type="info" title="Agrupando ticketOptions con area" %}
El campo `area` en `ticketOption` **es opcional** y sirve para **agrupar categorías ubicadas en una zona similar** del venue. Varios ticketOptions pueden compartir el mismo valor de `area`.

Por ejemplo, si en "Platea Alta" tenés tres categorías comerciales diferentes (`Platea Alta VIP`, `Platea Alta Regular`, `Platea Alta Discapacitados`), las tres pueden declarar `"area": "Platea Alta"`. menta usa ese agrupador para filtros, navegación y métricas por zona.
{% /callout %}
{% /tab %}

{% tab label="Carga manual de eventos" %}
## Carga manual

Para volúmenes bajos o pruebas piloto, es posible cargar eventos mediante archivos (CSV/Excel) procesados por el equipo de operaciones de menta.

Este método no requiere desarrollo pero tiene limitaciones operativas importantes y riesgo de desactualización de datos. Contacta a tu account manager si deseas utilizar esta opción.
{% /tab %}
{% /conditionaltabs %}

---

## Estado del Show

Cada show incluye un campo `status` que representa su estado actual en el ciclo de vida. Este estado determina cómo se muestra el show y si la actividad de reventa está habilitada.

{% table highlight-first=true %}
| Estado | Descripción | Visible al público | Reventa habilitada |
| :--- | :--- | :--- | :--- |
| `ON_SALE` | Los boletos se están vendiendo activamente en el mercado primario. El show es visible públicamente y la reventa está completamente operativa. | Sí | Sí |
| `ANNOUNCED` | El show ha sido anunciado públicamente y es visible, pero la venta primaria de boletos aún no ha comenzado o fue pausada. Los usuarios pueden ver el evento pero no pueden comprar boletos en el mercado primario. La reventa puede seguir activa si los boletos fueron distribuidos previamente. | Sí | Depende de la configuración |
| `CANCELLED` | El show ha sido cancelado. No se permite más actividad de venta ni reventa. Las publicaciones de reventa existentes se eliminan y las transacciones pendientes se manejan según la política de cancelación. | Sí (marcado como cancelado) | No |
| `RESCHEDULED` | El show fue movido a una nueva fecha u horario. El campo `dates.startsAt` refleja la nueva programación. La actividad de reventa puede continuar bajo la nueva fecha dependiendo de la configuración. | Sí (marcado como reprogramado) | Depende de la configuración |
| `HIDDEN` | El show no es visible al público. No aparece en resultados de búsqueda, listados de eventos ni en el marketplace de reventa. Se usa típicamente para shows en preparación o temporalmente removidos. | No | No |
| `PRIVATE` | El show está restringido a una audiencia específica (ej., solo invitados, grupos de preventa o eventos internos). No es visible en listados públicos pero puede ser accesible mediante link directo o código de acceso. | Solo con acceso directo | Depende de la configuración |
{% /table %}

{% callout type="info" title="Estado y fechas" %}
El campo `status` refleja el **estado operativo actual** del show, mientras que el objeto `dates` proporciona la **línea de tiempo programada**. Por ejemplo, un show puede tener `status: "ANNOUNCED"` con un `dates.salesStartAt` en el futuro — lo que significa que pasará automáticamente a estar en venta en esa fecha. Envía siempre ambos campos para que menta tech pueda gestionar el ciclo de vida del show correctamente.
{% /callout %}

## Fechas del Show

El objeto `dates` agrupa todas las fechas relevantes del ciclo de vida de un show. Todas las fechas deben estar en formato ISO 8601.

{% table highlight-first=true %}
| Campo | Descripción |
| :--- | :--- |
| `dates.startsAt` | Fecha y hora de inicio del show (el horario de la función). Es la fecha de referencia principal del evento. |
| `dates.salesStartAt` | Fecha y hora en que abre la venta primaria de boletos. Antes de esta fecha, los boletos no pueden comprarse en el mercado primario. |
| `dates.salesEndAt` | Fecha y hora en que cierra la venta primaria de boletos. Después de esta fecha, los boletos ya no están disponibles en el mercado primario. |
| `dates.publicAt` | Fecha y hora en que el show se hace visible públicamente en la web. Antes de esta fecha, el show puede existir internamente pero no se muestra a los usuarios finales. |
{% /table %}

---

## Cancelación de Eventos

{% callout type="warning" title="Importancia crítica" %}
**Es fundamental informar a menta tech cuando un evento es cancelado.** La distribución del dinero a los vendedores de boletos de reventa se realiza unos días después de la fecha original del evento. Si un evento se cancela y no se notifica a menta, los pagos se procesarán normalmente después de la fecha programada y **no habrá forma de recuperar el dinero** una vez distribuido.
{% /callout %}

### ¿Por qué es tan importante?

Cuando un evento se cancela:
1. **Los compradores de reventa deben ser reembolsados** - menta gestiona automáticamente los reembolsos si se notifica la cancelación a tiempo.
2. **Los pagos a vendedores se detienen** - si no se informa la cancelación, los vendedores recibirán el pago como si el evento se hubiera realizado.
3. **No hay recuperación posterior** - una vez que los fondos son distribuidos, no es posible revertir las transacciones.

### Cómo notificar una cancelación

{% conditionaltabs id="tabs-cancellation" %}

{% tab label="API de menta tech" %}
### Cancelación vía API (Recomendado)

Para cancelar un evento mediante la API, utiliza el endpoint de cancelación:

```bash
POST /v1/events/:externalReferenceId/cancellation
```

Donde `:externalReferenceId` es el identificador único del evento en tu sistema de ticketing.

**Parámetros opcionales:**
- `showId`: Si solo deseas cancelar un show específico dentro del evento, incluye este parámetro en el query string.

{% apiembed endpoint="post-post-events-id-cancellation" show="link" width="auto" /%}

{% /tab %}

{% tab label="Endpoint expuesto por tu plataforma" %}
### Cancelación con integración Pull

Si tu integración es mediante un endpoint que menta consulta periódicamente, tienes dos opciones:

**Opción 1: Feed de eventos cancelados**
Exponer un endpoint adicional (ej: `https://api.tuplataforma.com/menta-feed/cancelled`) que devuelva la lista de eventos cancelados. menta consultará este feed periódicamente.

```json
[
  {
    "externalReferenceId": "evt_example_001",
    "cancelledAt": "2025-01-15T10:30:00.000Z",
    "showId": "show_001" // opcional, si es solo un show
  }
]
```

**Opción 2: API Call directo (Recomendado)**
Aunque tu integración principal sea mediante pull, **recomendamos utilizar el API call de cancelación** para notificaciones en tiempo real:

```bash
POST /v1/events/:externalReferenceId/cancellation
```

Esto garantiza que la cancelación se procese inmediatamente sin esperar al siguiente ciclo de polling.
{% /tab %}

{% tab label="Carga manual de eventos" %}
### Cancelación con carga manual

Para integraciones de carga manual, tienes dos opciones:

**Opción 1: API Call (Recomendado)**
Aunque la carga de eventos sea manual, recomendamos implementar el API call de cancelación:

```bash
POST /v1/events/:externalReferenceId/cancellation
```

**Opción 2: Notificación al Account Manager**
Dado que este tipo de integración está orientado a plataformas con menor volumen, también es posible informar la cancelación directamente a tu account manager. Sin embargo, esto puede generar demoras en el procesamiento.

{% callout type="info" %}
Contacta a tu account manager lo antes posible cuando un evento sea cancelado para evitar pagos incorrectos.
{% /callout %}
{% /tab %}

{% /conditionaltabs %}
