# Webhooks

## Descripción General

Los **webhooks** permiten a menta tech notificar a tu plataforma en tiempo real cada vez que ocurre un evento relevante en el ecosistema de reventa. En lugar de consultar periódicamente por cambios, tu sistema recibe solicitudes HTTP POST con datos estructurados del evento en el momento en que ocurren.

Los webhooks son esenciales para:

* Mantener tu plataforma sincronizada con la actividad de reventa
* Disparar procesos posteriores (entrega de boletos, reportes, actualizaciones de CRM)
* Rastrear la actividad del marketplace (publicaciones, ventas, pagos)
* Habilitar notificaciones en tiempo real para los usuarios

## Estructura General del Payload

Cada webhook enviado por menta tech sigue un formato de envoltorio consistente:

```json
{
  "message": {
    "family": "<familia_del_evento>",
    "action": "<accion_del_evento>",
    "type": "<subtipo_del_evento>",
    "data": { ... }
  }
}
```

{% table highlight-first=true %}
| Campo | Descripción |
| :--- | :--- |
| `family` | Agrupa eventos relacionados (ej., `listing`, `ticket`, `event`, `notifyMe`, `payouts`). |
| `action` | El evento específico que ocurrió (ej., `listing.created`, `ticket.updated`). |
| `type` | Proporciona contexto adicional sobre la variante del evento (ej., `SINGLE`, `MULTI`, `USER_TRANSFER`). No está presente en todos los eventos. |
| `data` | El payload específico del evento con la información relevante. |
{% /table %}

## Resumen de Eventos

{% table highlight-first=true %}
| Familia | Acción | Descripción |
| :--- | :--- | :--- |
| **listing** | `listing.created` | Se publicó una nueva publicación en el mercado secundario. |
| **listing** | `listing.updated` | Se modificó una publicación existente (ej., cambio de precio). |
| **listing** | `listing.deleted` | Se eliminó una publicación del mercado secundario. |
| **ticket** | `ticket.updated` | Se completó una reventa y cambió el dueño del boleto. |
| **event** | `event.unlock` | Se desbloquearon los boletos de un evento. |
| **notifyMe** | `notifyMe.created.updated` | Se creó o actualizó una suscripción de "Avisarme". |
| **payouts** | `payouts.delivered` | Se enviaron los pagos a los vendedores de un evento/show. |
{% /table %}

---

## Notas Importantes sobre Identificadores

{% callout type="warning" %}
La mayoría de los identificadores en los payloads de webhooks — como `ticketId`, `eventId`, `showId` y el campo `id` en `ticket.updated` — provienen de **tu plataforma**. Corresponden a los IDs que asignaste al crear o sincronizar estos recursos con menta tech.

Los siguientes identificadores son generados por **menta tech**:
* `listingId` — Identificador único de una publicación en el marketplace.
* `groupId` — Agrupa boletos dentro de una misma operación de publicación.
* `resaleId` — Identificador único de una transacción de reventa completada.
* `id` (en eventos `notifyMe`) — Identificador único de una suscripción de "Avisarme".
{% /callout %}

---

## Detalle de Eventos

{% conditionaltabs id="tabs-webhooks-families" %}
{% tab label="Listing" %}
## Eventos de Listing

Los eventos de listing notifican a tu plataforma sobre cambios en el inventario del marketplace de reventa. Se disparan cada vez que un usuario crea, actualiza o elimina una publicación de boletos.

El campo `type` en los eventos de listing indica si la publicación involucra un solo boleto (`SINGLE`) o múltiples boletos (`MULTI`).

### listing.created

Se dispara cuando un usuario publica una nueva oferta en el mercado secundario.

```json
{
  "message": {
    "family": "listing",
    "action": "listing.created",
    "type": "MULTI",
    "data": {
      "ticketId": "5102",
      "sellerEmail": "maria.becerra@example.com",
      "listingId": "70cde790d4e17236e08587g2",
      "listingPrice": 1500,
      "listingFinalPrice": 1725,
      "listingPayout": {
        "type": "LOCAL_FIAT_AUTOMATIC",
        "data": {
          "paymentMethod": "emoneyout-mxn_012",
          "userForm": {
            "beneficiary_name": "Maria",
            "beneficiary_lastname": "Becerra",
            "bank_account": "014027000012345678",
            "bank_account_type": "checking"
          }
        }
      },
      "groupId": "70cde790d4e17236e08587ec"
    }
  }
}
```

### listing.updated

Se dispara cuando un usuario modifica una publicación existente (ej., cambio de precio).

```json
{
  "message": {
    "family": "listing",
    "action": "listing.updated",
    "type": "SINGLE",
    "data": {
      "ticketId": "T3FB2E891AA4208",
      "listingId": "70cedef51c3fcd8f74d0e4e1",
      "listingPrice": 14,
      "listingFinalPrice": 16.1,
      "listingPayout": {
        "type": "LOCAL_FIAT_AUTOMATIC",
        "data": {
          "paymentMethod": "dlocal-emoneyout-mxn_138",
          "userForm": {
            "beneficiary_name": "Jorge",
            "beneficiary_lastname": "Ramirez",
            "bank_account": "072180001098765432"
          }
        }
      },
      "groupId": "70cedef51c3fcd8f74d0e4d8",
      "sellerEmail": "jorge.ramirez@example.com"
    }
  }
}
```

### listing.deleted

Se dispara cuando se elimina una publicación del mercado secundario, ya sea por el usuario o por el sistema.

```json
{
  "message": {
    "family": "listing",
    "action": "listing.deleted",
    "type": "MULTI",
    "data": {
      "ticketId": "5102",
      "sellerEmail": "maria.becerra@example.com",
      "listingId": "70cde6551b66d4098c5523dc",
      "listingPrice": 1500,
      "listingFinalPrice": 1725,
      "listingPayout": {
        "type": "LOCAL_FIAT_AUTOMATIC",
        "data": {
          "paymentMethod": "emoneyout-mxn_012",
          "userForm": {
            "beneficiary_name": "Maria",
            "beneficiary_lastname": "Becerra",
            "bank_account": "014027000012345678",
            "bank_account_type": "checking"
          }
        }
      },
      "groupId": "70cde6551b66d4098c5523dc"
    }
  }
}
```

### Campos del Payload de Listing

| Campo | Descripción | Origen del ID |
| :--- | :--- | :--- |
| `ticketId` | El identificador del boleto. | Tu plataforma |
| `sellerEmail` | Email o número de teléfono del vendedor. | — |
| `listingId` | Identificador único de la publicación. | menta tech |
| `listingPrice` | El precio establecido por el vendedor (antes de comisiones). | — |
| `listingFinalPrice` | El precio final para el comprador (incluyendo comisiones). | — |
| `listingPayout` | Configuración y método de pago para el vendedor. | — |
| `groupId` | Identificador que agrupa múltiples boletos en una misma operación de publicación. | menta tech |

{% /tab %}
{% tab label="Ticket" %}
## Eventos de Ticket

### ticket.updated

Se dispara cuando se completa una transacción de reventa y la propiedad del boleto cambia del vendedor al comprador. Este es el evento clave para iniciar la entrega del boleto en tu plataforma.

```json
{
  "message": {
    "family": "ticket",
    "action": "ticket.updated",
    "type": "USER_TRANSFER",
    "data": {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "newOwnerEmail": "carlos.lopez@example.com",
      "oldOwnerEmail": "ana.martinez@example.com",
      "reversal": false,
      "metadata": {
        "nominal": {
          "fullName": "Carlos Lopez",
          "identificationType": "DNI",
          "identification": "30567890",
          "externalEmail": "carlos.lopez@example.com",
          "email": "carlos.lopez@example.com"
        },
        "payer": {
          "fullName": "Carlos Lopez",
          "identificationType": "DNI",
          "identification": "30567890",
          "externalEmail": "carlos.lopez@example.com",
          "email": "carlos.lopez@example.com"
        },
        "seller": {
          "fullName": "Ana Martinez",
          "identification": "28901234",
          "identificationType": "DNI"
        },
        "order": {
          "resaleId": "70ceeed4d4e17236e085e472",
          "grossResalePaidAmount": 103816.25,
          "grossResalePaidAmountWithoutBuyerFee": 90275,
          "sellerFee": 0.15,
          "sellerFeeAmount": 11775,
          "buyerFee": 0.15,
          "buyerFeeAmount": 13541.25
        }
      }
    }
  }
}
```

{% callout type="info" %}
Este es el webhook más crítico para la entrega de boletos. Cuando recibas un evento `ticket.updated`, tu plataforma debe iniciar inmediatamente el proceso de entrega del boleto al nuevo dueño.
{% /callout %}

{% callout type="warning" title="Reversiones de transacción" %}
Cuando `reversal` es `true`, la transacción se está revirtiendo — el boleto debe ser devuelto al dueño anterior. En este caso, `metadata.nominal` contiene la información del dueño anterior (si está disponible). Tu plataforma debe deshacer la transferencia original de forma acorde.
{% /callout %}

### Campos del Payload de ticket.updated

| Campo | Descripción | Origen del ID |
| :--- | :--- | :--- |
| `id` | El identificador del boleto. | Tu plataforma |
| `newOwnerEmail` | Email del comprador (nuevo dueño del boleto). | — |
| `oldOwnerEmail` | Email del vendedor (dueño anterior del boleto). | — |
| `reversal` | `true` si la transacción se está revirtiendo (ej., contracargo, reembolso). Cuando es `true`, `metadata.nominal` contiene los datos del dueño anterior si están disponibles. Por defecto es `false`. | — |
| `metadata.nominal` | Datos de identidad de la persona a quien está asignado nominalmente el boleto. | — |
| `metadata.payer` | Datos de identidad de la persona que pagó por el boleto. | — |
| `metadata.seller` | Datos de identidad del vendedor. | — |
| `metadata.order.resaleId` | Identificador único de la transacción de reventa. | menta tech |
| `metadata.order.grossResalePaidAmount` | Monto total pagado por el comprador (incluyendo todas las comisiones). | — |
| `metadata.order.grossResalePaidAmountWithoutBuyerFee` | Monto pagado excluyendo la comisión del comprador. | — |
| `metadata.order.sellerFee` | Comisión del vendedor como decimal (ej., `0.15` = 15%). | — |
| `metadata.order.sellerFeeAmount` | Monto absoluto de la comisión del vendedor descontado de la venta. | — |
| `metadata.order.buyerFee` | Comisión del comprador como decimal (ej., `0.15` = 15%). | — |
| `metadata.order.buyerFeeAmount` | Monto absoluto de la comisión del comprador sumado al precio de venta. | — |

{% /tab %}
{% tab label="Event" %}
## Eventos de Event

### event.unlock

Se dispara cuando se desbloquean los boletos de un evento. Esto ocurre típicamente cuando el organizador del evento habilita o modifica la actividad de reventa.

{% callout type="warning" %}
Después de un `event.unlock`, las publicaciones existentes pueden seguir activas en el marketplace, pero no se pueden crear nuevas publicaciones. Tu plataforma debe tener esto en cuenta al mostrar opciones de reventa a los usuarios.
{% /callout %}

```json
{
  "message": {
    "family": "event",
    "action": "event.unlock",
    "data": {
      "eventId": "8544",
      "showId": "8544",
      "excludedEmailTicketIds": []
    }
  }
}
```

### Campos del Payload de event.unlock

| Campo | Descripción | Origen del ID |
| :--- | :--- | :--- |
| `eventId` | El identificador del evento. | Tu plataforma |
| `showId` | El identificador del show. | Tu plataforma |
| `excludedEmailTicketIds` | Lista de IDs de boletos excluidos de la operación de desbloqueo. Cuando está vacía, todos los boletos están incluidos. | Tu plataforma |

{% /tab %}
{% tab label="Notify Me" %}
## Eventos de Notify Me

### notifyMe.created.updated

Se dispara cuando un usuario crea o actualiza una suscripción de "Avisarme". Estas suscripciones permiten a los usuarios expresar interés en boletos de un evento específico y ser notificados cuando haya boletos disponibles que coincidan con sus preferencias de precio.

```json
{
  "message": {
    "family": "notifyMe",
    "action": "notifyMe.created.updated",
    "data": {
      "id": "70cedf0685b7a892dc5c9418",
      "showId": "7322",
      "eventId": "7322",
      "userEmail": "pedro.sanchez@example.com",
      "status": "ACTIVE",
      "ticketQuantity": 1,
      "ticketOptionSelections": [
        {
          "ticketOptionId": "36790",
          "priceLimit": 13799
        },
        {
          "ticketOptionId": "36821",
          "priceLimit": 17250
        },
        {
          "ticketOptionId": "36822",
          "priceLimit": 20700
        },
        {
          "ticketOptionId": "37489",
          "priceLimit": 110400
        },
        {
          "ticketOptionId": "38029",
          "priceLimit": 4140
        }
      ],
      "createdAt": "2026-03-20T22:49:41.338Z",
      "updatedAt": "2026-03-20T23:45:57.869Z"
    }
  }
}
```

### Campos del Payload de notifyMe.created.updated

| Campo | Descripción | Origen del ID |
| :--- | :--- | :--- |
| `id` | Identificador único de la suscripción. | menta tech |
| `showId` | El identificador del show. | Tu plataforma |
| `eventId` | El identificador del evento. | Tu plataforma |
| `userEmail` | Email del usuario suscrito. | — |
| `status` | Estado actual de la suscripción (ej., `ACTIVE`). | — |
| `ticketQuantity` | Cantidad de boletos que busca el usuario. | — |
| `ticketOptionSelections` | Arreglo de categorías de boletos con preferencias de precio máximo. | — |
| `ticketOptionSelections[].ticketOptionId` | El identificador de la opción/categoría de boleto. | Tu plataforma |
| `ticketOptionSelections[].priceLimit` | Precio máximo que el usuario está dispuesto a pagar por esa categoría. | — |
| `createdAt` | Timestamp ISO 8601 de creación de la suscripción. | — |
| `updatedAt` | Timestamp ISO 8601 de la última actualización. | — |

{% /tab %}
{% tab label="Payouts" %}
## Eventos de Payouts

### payouts.delivered

Se dispara cuando los pagos de un evento o show específico han sido procesados y enviados a los vendedores.

```json
{
  "message": {
    "family": "payouts",
    "action": "payouts.delivered",
    "data": {
      "showId": "239616",
      "eventId": "12746"
    }
  }
}
```

### Campos del Payload de payouts.delivered

| Campo | Descripción | Origen del ID |
| :--- | :--- | :--- |
| `showId` | El identificador del show para el cual se procesaron los pagos. | Tu plataforma |
| `eventId` | El identificador del evento para el cual se procesaron los pagos. | Tu plataforma |

{% /tab %}
{% /conditionaltabs %}
