> ## Documentation Index
> Fetch the complete documentation index at: https://restoo.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Eventos del widget de Restoo

> Eventos que emite el widget de Restoo, sus payloads y cómo escucharlos.

El widget de Restoo emite [eventos personalizados de navegador](https://developer.mozilla.org/es/docs/Web/API/CustomEvent) para los pasos principales del embudo de reserva. Escúchalos con [listeners de eventos](https://developer.mozilla.org/es/docs/Web/API/EventTarget/addEventListener) estándar para medir el embudo en tu propia analítica, o en cualquier otro sistema que consuma eventos de navegador.

<Tip>
  Si usas GA4, Google Ads, Meta Pixel, TikTok Pixel, OpenAI Pixel o Google Tag Manager,
  consulta [Restoo Connect](/es/widget/connect). Reenvía estos eventos sin
  necesidad de un listener a medida para cada uno.
</Tip>

## Escuchar los eventos

Cada evento es un `CustomEvent` estándar del navegador. Su nombre empieza por `restoo:` y su payload está disponible en `event.detail`.

Por ejemplo, para recibir una reserva confirmada:

```js theme={null}
window.addEventListener("restoo:booking_created", (event) => {
  const { booking } = event.detail.data;

  console.log("Reserva confirmada:", booking.date, booking.time, booking.pax);
});
```

Registra tus listeners en la página que incrusta el widget.

<Note>
  **Estos eventos llegan siempre, con o sin consentimiento.** El widget los emite
  en tu página para que midas con tus propias herramientas; lo que el
  consentimiento controla es lo que [Restoo Connect](/es/widget/connect) entrega a
  cada plataforma. Si los reenvías a un tercero, el consentimiento lo aplicas tú.
  La excepción es la identidad del cliente: el correo y el teléfono hasheados solo
  se emiten con el permiso de publicidad concedido ([identidad del
  cliente](/es/widget/consent#identidad-del-cliente)).
</Note>

## Referencia de eventos

### Widget y navegación

| Evento                  | Cuándo se dispara                                                  | `data`                        |
| ----------------------- | ------------------------------------------------------------------ | ----------------------------- |
| `restoo:widget_mounted` | El widget se ha montado y los datos del negocio están disponibles. | [`WidgetEvent`](#widgetevent) |
| `restoo:page_viewed`    | El visitante navega a una página del widget.                       | [`PageViewed`](#pageviewed)   |

### Embudo de reserva

| Evento                                  | Cuándo se dispara                                                                       | `data`                              |
| --------------------------------------- | --------------------------------------------------------------------------------------- | ----------------------------------- |
| `restoo:booking_start_viewed`           | Se muestra la página de inicio de reserva.                                              | `null`                              |
| `restoo:booking_start_submitted`        | Se envía la búsqueda de disponibilidad con un número de comensales y una fecha válidos. | [`BookingFunnel`](#bookingfunnel)   |
| `restoo:booking_no_availability_viewed` | La búsqueda actual no tiene disponibilidad.                                             | [`NoAvailability`](#noavailability) |
| `restoo:booking_conditions_viewed`      | Se muestran las condiciones opcionales de la reserva.                                   | [`BookingFunnel`](#bookingfunnel)   |
| `restoo:booking_conditions_accepted`    | El visitante acepta las condiciones de la reserva.                                      | [`BookingFunnel`](#bookingfunnel)   |
| `restoo:booking_details_form_viewed`    | Se muestra el formulario de datos del cliente.                                          | [`BookingFunnel`](#bookingfunnel)   |
| `restoo:booking_details_form_started`   | El visitante empieza a rellenar el formulario de datos del cliente.                     | [`BookingFunnel`](#bookingfunnel)   |
| `restoo:booking_details_form_submitted` | Los datos del cliente se guardan correctamente.                                         | [`BookingFunnel`](#bookingfunnel)   |
| `restoo:booking_cp_viewed`              | Se muestra una política de cancelación aplicable.                                       | [`BookingFunnel`](#bookingfunnel)   |
| `restoo:booking_cp_acknowledged`        | El visitante marca «he leído y acepto» la política de cancelación.                      | [`BookingFunnel`](#bookingfunnel)   |
| `restoo:booking_cp_accepted`            | Se acepta la política de cancelación: la tarjeta se valida correctamente.               | [`BookingFunnel`](#bookingfunnel)   |
| `restoo:booking_created`                | Se crea una reserva nueva.                                                              | [`BookingFunnel`](#bookingfunnel)   |
| `restoo:booking_updated`                | Se modifica una reserva existente.                                                      | [`BookingFunnel`](#bookingfunnel)   |

<Note>
  Algunos eventos dependen de la configuración de la reserva. Por ejemplo, los
  eventos de condiciones y de política de cancelación solo aparecen cuando esos
  pasos se presentan.
</Note>

<Note>
  Estos dos eventos son mutuamente excluyentes y se disparan una vez cada vez que
  se guarda una reserva, en el momento en que el backend la confirma, no cuando se
  renderiza la página de confirmación, así que recargar esa página no los vuelve a
  emitir. Modificar una reserva emite `booking_updated`, nunca `booking_created`.
  Los dos llevan `is_update_flow` con el valor correspondiente.
</Note>

### Eventos de listado de elementos

| Evento                              | Cuándo se dispara                                              | `data`                                            |
| ----------------------------------- | -------------------------------------------------------------- | ------------------------------------------------- |
| `restoo:booking_item_list_viewed`   | Se muestra un listado de experiencias, horas o complementos.   | [`BookingViewItemList`](#bookingviewitemlist)     |
| `restoo:booking_item_detail_viewed` | El visitante abre el detalle de una experiencia o de una zona. | [`BookingViewItemDetail`](#bookingviewitemdetail) |
| `restoo:booking_item_selected`      | El visitante selecciona uno o varios elementos de un listado.  | [`BookingSelectItem`](#bookingselectitem)         |

### Cliente

| Evento                       | Cuándo se dispara                                                            | `data`                                      |
| ---------------------------- | ---------------------------------------------------------------------------- | ------------------------------------------- |
| `restoo:customer_identified` | Se identifica a un cliente desde el formulario o desde los datos recordados. | [`CustomerIdentified`](#customeridentified) |
| `restoo:customer_signed_out` | El cliente cierra la sesión de los datos recordados.                         | `null`                                      |

<Warning>
  `customer_identified` lleva datos personales, así que se emite **solo cuando el
  visitante ha concedido `ad_user_data`**: consulta
  [Consentimiento](/es/widget/consent#identidad-del-cliente). No se pierde si el
  permiso llega más tarde: el widget retiene la identificación y la emite en cuanto
  el visitante la concede, que es lo que ocurre cuando se reconoce a alguien por
  sus datos recordados antes de que responda al aviso de cookies.
</Warning>

### Acciones

| Evento                | Cuándo se dispara                                                                                                                                            | `data`                        |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------- |
| `restoo:action_taken` | El visitante usa una acción importante, como contactar, añadir al calendario, obtener indicaciones, compartir o una alternativa por falta de disponibilidad. | [`ActionTaken`](#actiontaken) |

## Campos comunes a todos los eventos

Todos los eventos tienen la misma estructura de primer nivel en `event.detail`:

```js theme={null}
{
  id: "550e8400-e29b-41d4-a716-446655440000",
  session_id: "f47ac10b-58cc-4372-a567-0e02b2c3d479",
  name: "booking_created",
  type: "booking",
  timestamp: "2026-07-22T10:15:00.000Z",
  source: {
    account_id: "best-burger",
    widget_id: "restoo_w-reservations",
    widget_display_mode: "INLINE",
    business_name: "Best Burger"
  },
  acquisition: {
    utm_source: "google",
    utm_medium: "cpc",
    utm_campaign: "summer",
    utm_content: null,
    utm_term: null
  },
  is_update_flow: false,
  data: {
    // La forma depende del evento.
  }
}
```

**Campos**

<ResponseField name="id" type="string" required>
  Identificador único de **esta emisión**, no del tipo de evento. Los navegadores
  modernos generan un UUID RFC 4122, pero trátalo como una cadena opaca, porque el
  método alternativo que usan los navegadores antiguos tiene otro formato.

  Cada emisión recibe uno nuevo: tres clics en el botón de contacto producen tres
  eventos `action_taken` con tres valores de `id` distintos.
</ResponseField>

<ResponseField name="session_id" type="string" required>
  Identificador compartido por los eventos de una misma sesión del widget. Sigue
  las mismas reglas de formato que `id`.
</ResponseField>

<ResponseField name="name" type="string" required>
  Nombre del evento sin el prefijo `restoo:`.
</ResponseField>

<ResponseField name="type" type="string | null" required>
  Modelo del payload. Determina la forma de `data`; tanto `type` como `data` son
  `null` en los eventos que no llevan payload.

  | Valor                      | Valores de `name`                                                                                                                                                                                                                                                                                   | Forma de `data`                                   |
  | -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------- |
  | `widget`                   | `widget_mounted`                                                                                                                                                                                                                                                                                    | [`WidgetEvent`](#widgetevent)                     |
  | `page_view`                | `page_viewed`                                                                                                                                                                                                                                                                                       | [`PageViewed`](#pageviewed)                       |
  | `booking`                  | `booking_start_submitted`, `booking_conditions_viewed`, `booking_conditions_accepted`, `booking_details_form_viewed`, `booking_details_form_started`, `booking_details_form_submitted`, `booking_cp_viewed`, `booking_cp_acknowledged`, `booking_cp_accepted`, `booking_created`, `booking_updated` | [`BookingFunnel`](#bookingfunnel)                 |
  | `no_availability`          | `booking_no_availability_viewed`                                                                                                                                                                                                                                                                    | [`NoAvailability`](#noavailability)               |
  | `booking_view_item_list`   | `booking_item_list_viewed`                                                                                                                                                                                                                                                                          | [`BookingViewItemList`](#bookingviewitemlist)     |
  | `booking_view_item_detail` | `booking_item_detail_viewed`                                                                                                                                                                                                                                                                        | [`BookingViewItemDetail`](#bookingviewitemdetail) |
  | `booking_select_item`      | `booking_item_selected`                                                                                                                                                                                                                                                                             | [`BookingSelectItem`](#bookingselectitem)         |
  | `customer_identification`  | `customer_identified`                                                                                                                                                                                                                                                                               | [`CustomerIdentified`](#customeridentified)       |
  | `action`                   | `action_taken`                                                                                                                                                                                                                                                                                      | [`ActionTaken`](#actiontaken)                     |
  | `null`                     | `booking_start_viewed`, `customer_signed_out`                                                                                                                                                                                                                                                       | `null`                                            |
</ResponseField>

<ResponseField name="timestamp" type="string" required>
  Hora del evento como marca temporal ISO 8601 en UTC. Ejemplo:
  `"2026-07-22T10:15:00.000Z"`.
</ResponseField>

<ResponseField name="source" type="object" required>
  Contexto del widget.

  <Expandable title="propiedades">
    <ResponseField name="account_id" type="string" required>
      Identificador de la cuenta del restaurante. Ejemplo: `"best-burger"`.
    </ResponseField>

    <ResponseField name="widget_id" type="string" required>
      Identificador del widget. Ejemplo: `"restoo_w-reservations"`.
    </ResponseField>

    <ResponseField name="widget_display_mode" type="string" required>
      Modo de presentación que usa el widget.

      | Valor     | Significado                                                   |
      | --------- | ------------------------------------------------------------- |
      | `INLINE`  | El widget se renderiza dentro de la maquetación de tu página. |
      | `OVERLAY` | El widget se abre por encima de tu página.                    |
    </ResponseField>

    <ResponseField name="business_name" type="string" required>
      Nombre público del negocio. Ejemplo: `"Best Burger"`.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="acquisition" type="object" required>
  Atribución de marketing asociada a la visita.

  <Expandable title="propiedades">
    <ResponseField name="utm_source" type="string | null" required>
      Fuente de tráfico UTM, o `null` si no está presente.
    </ResponseField>

    <ResponseField name="utm_medium" type="string | null" required>
      Medio de marketing UTM, o `null` si no está presente.
    </ResponseField>

    <ResponseField name="utm_campaign" type="string | null" required>
      Nombre de la campaña UTM, o `null` si no está presente.
    </ResponseField>

    <ResponseField name="utm_content" type="string | null" required>
      Identificador de contenido UTM, o `null` si no está presente.
    </ResponseField>

    <ResponseField name="utm_term" type="string | null" required>
      Término de búsqueda de pago UTM, o `null` si no está presente.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="is_update_flow" type="boolean" required>
  `true` cuando el evento pertenece a un flujo de modificación; en caso contrario, `false`.
</ResponseField>

<ResponseField name="data" type="object | null" required>
  Payload propio de cada evento. Consulta [Datos de los eventos](#datos-de-los-eventos) para más información.
</ResponseField>

## Datos de los eventos

Los ejemplos de abajo muestran el valor de `event.detail.data`, no el evento completo.

Definiciones: [`WidgetEvent`](#widgetevent), [`PageViewed`](#pageviewed),
[`BookingFunnel`](#bookingfunnel), [`NoAvailability`](#noavailability),
[`BookingViewItemList`](#bookingviewitemlist),
[`BookingSelectItem`](#bookingselectitem),
[`BookingViewItemDetail`](#bookingviewitemdetail),
[`ActionTaken`](#actiontaken) y
[`CustomerIdentified`](#customeridentified).

<Note>
  ¿Buscas un campo que no está aquí, como el nombre de un elemento del catálogo o
  más datos del cliente? Algunos se omiten a propósito; consulta [Qué omite Restoo
  deliberadamente](/es/widget/connect-mappings#qué-omite-restoo-deliberadamente).
</Note>

### WidgetEvent

Lo usa `widget_mounted`.

```json theme={null}
{
  "url": "https://best-burger.myrestoo.net/widget/restooWidget.html?view=experiences"
}
```

**Campos**

<ResponseField name="url" type="string" required>
  URL del documento interno que Restoo carga dentro del iframe.

  **No es la URL de tu página, y no es una dirección que puedas abrir**: por sí
  sola se queda en blanco, porque el widget no dibuja nada hasta que Restoo.js le
  manda los ajustes al montarlo.

  La ruta es siempre la misma y solo cambian sus parámetros, así que este campo
  identifica la vista de arranque, no dónde estaba el visitante. Para eso lee
  `window.location.href` en tu propia página.
</ResponseField>

### PageViewed

Lo usa `page_viewed`.

```json theme={null}
{
  "page_name": "reservation"
}
```

**Campos**

<ResponseField name="page_name" type="string" required>
  Ruta interna de la vista; refleja las propias rutas del widget, una por
  pantalla (hay más de 50). Algunos ejemplos representativos: `"reservation"`
  (calendario), `"reservation/details"` (formulario de datos del cliente),
  `"reservation/confirmed"`, `"experiences"`, `"store"`, `"store/checkout"`,
  `"booking/cancel"` y `"my-account"`.
</ResponseField>

### BookingFunnel

Lo usan los eventos del embudo de reserva cuyo `type` es `booking`. El payload es una **instantánea de la reserva en el momento en que se emite el evento**, así que los campos que todavía no se han seleccionado o asignado pueden valer `null`.

```js theme={null}
{
  booking: {
    account_id: "best-burger",
    status: "CONFIRMED",
    shift_type: {
      id: "DINNER",
      name: "Dinner"
    },
    pax: 2,
    pax_children: 0,
    high_chairs: 0,
    strollers: 0,
    date: "2026-07-25",
    weekday: "saturday",
    time: "20:30:00",
    floor_plan_area: {
      id: "best_burger:floor_plan_area:3",
      name: "Terrace"
    },
    experience: {
      id: "best_burger:experience:7",
      price_per_ticket: 6500,
      currency: "EUR",
      tickets: 2
    },
    add_ons: [
      {
        id: "best_burger:add_on:12",
        unit_price: 2500,
        currency: "EUR",
        quantity: 2
      }
    ],
    currency: "EUR",
    total_amount: 18000,
    is_time_limited: false,
    cancellation_policy: {
      type: "PREPAYMENT",
      amount: 3000,
      amount_type: "PER_PAX",
      cancellation_fee_amount: 6000,
      charged_amount: 6000,
      cancellation_notice_hours: 24,
      currency: "EUR"
    }
  }
}
```

**Campos**

<ResponseField name="booking" type="object" required>
  Estado de la reserva en el momento de emitir el evento.

  <Expandable title="propiedades">
    <ResponseField name="account_id" type="string" required>
      Identificador de la cuenta del restaurante. Ejemplo: `"best-burger"`.
    </ResponseField>

    <ResponseField name="status" type="string" required>
      Estado actual de la reserva. Consulta
      [BookingStatus](/getting-started/enums#bookingstatus) para los valores
      posibles y su significado. Durante una reserva nueva, los valores habituales
      son `CONFIRMED`, `REQUESTED` y `PENDING_WAIT_LIST_BOOKING`.
    </ResponseField>

    <ResponseField name="shift_type" type="object | null" required>
      Servicio al que pertenece la reserva, o `null` antes de que haya uno disponible.

      <Expandable title="propiedades">
        <ResponseField name="id" type="string" required>
          Tipo de servicio. Consulta [ShiftType](/getting-started/enums#shifttype)
          para los valores posibles y su significado. Ejemplo: `"DINNER"`.
        </ResponseField>

        <ResponseField name="name" type="string" required>
          Nombre público del servicio, tal como lo ha nombrado el negocio.
          Ejemplo: `"Dinner"`.
        </ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="pax" type="number" required>
      Número de comensales adultos. Ejemplo: `2`.
    </ResponseField>

    <ResponseField name="pax_children" type="number" required>
      Número de niños. Ejemplo: `0`.
    </ResponseField>

    <ResponseField name="high_chairs" type="number" required>
      Número de tronas solicitadas. Ejemplo: `0`.
    </ResponseField>

    <ResponseField name="strollers" type="number" required>
      Número de carritos de bebé. Ejemplo: `0`.
    </ResponseField>

    <ResponseField name="date" type="string" required>
      Fecha de calendario ISO 8601 en formato `YYYY-MM-DD`. Ejemplo:
      `"2026-07-25"`.
    </ResponseField>

    <ResponseField name="weekday" type="string | null" required>
      Día de la semana en inglés y en minúsculas correspondiente a `date`, o
      `null` cuando la fecha no es válida.

      | Valor       | Significado |
      | ----------- | ----------- |
      | `monday`    | Lunes.      |
      | `tuesday`   | Martes.     |
      | `wednesday` | Miércoles.  |
      | `thursday`  | Jueves.     |
      | `friday`    | Viernes.    |
      | `saturday`  | Sábado.     |
      | `sunday`    | Domingo.    |
    </ResponseField>

    <ResponseField name="time" type="string | null" required>
      Hora local del local en formato ISO 8601 `HH:mm:ss`, o `null` antes de que
      se seleccione una hora. Ejemplo: `"20:30:00"`.
    </ResponseField>

    <ResponseField name="floor_plan_area" type="object | null" required>
      Zona de mesas seleccionada, o `null` cuando no aplica ninguna zona.

      <Expandable title="propiedades">
        <ResponseField name="id" type="string" required>
          ID de recurso con espacio de nombres. Ejemplo:
          `"best_burger:floor_plan_area:3"`.
        </ResponseField>

        <ResponseField name="name" type="string" required>
          Nombre público de la zona. Ejemplo: `"Terrace"`.
        </ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="experience" type="object | null" required>
      Experiencia o menú seleccionados, o `null` cuando no aplica ninguno.

      <Expandable title="propiedades">
        <ResponseField name="id" type="string" required>
          ID de recurso con espacio de nombres. Ejemplo: `"best_burger:experience:7"`.
        </ResponseField>

        <ResponseField name="price_per_ticket" type="number" required>
          Precio por ticket en la unidad más pequeña de la divisa. Ejemplo: `6500`
          significa 65,00 € cuando `currency` es `EUR`.
        </ResponseField>

        <ResponseField name="currency" type="string" required>
          Código de divisa ISO 4217. Consulta
          [Currency](/getting-started/enums#currency) para más información.
        </ResponseField>

        <ResponseField name="tickets" type="number" required>
          Número de tickets de la experiencia seleccionados. Ejemplo: `2`.
        </ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="add_ons" type="object[]" required>
      Complementos seleccionados. El array está vacío cuando no hay ninguno.

      <Expandable title="propiedades de cada elemento">
        <ResponseField name="id" type="string" required>
          ID de recurso con espacio de nombres. Ejemplo: `"best_burger:add_on:12"`.
        </ResponseField>

        <ResponseField name="unit_price" type="number" required>
          Precio unitario en la unidad más pequeña de la divisa. Ejemplo: `2500`
          significa 25,00 € cuando `currency` es `EUR`.
        </ResponseField>

        <ResponseField name="currency" type="string" required>
          Código de divisa ISO 4217. Consulta
          [Currency](/getting-started/enums#currency) para más información.
        </ResponseField>

        <ResponseField name="quantity" type="number" required>
          Número de unidades seleccionadas. Ejemplo: `2`.
        </ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="currency" type="string" required>
      Código de divisa ISO 4217 del total de la reserva. Consulta
      [Currency](/getting-started/enums#currency) para más información.
    </ResponseField>

    <ResponseField name="total_amount" type="number" required>
      Precio total de la experiencia y los complementos en la unidad más pequeña
      de la divisa. Ejemplo: `18000` significa 180,00 € cuando `currency` es `EUR`.
    </ResponseField>

    <ResponseField name="is_time_limited" type="boolean" required>
      Indica si la franja horaria seleccionada tiene una hora de fin fija.
    </ResponseField>

    <ResponseField name="cancellation_policy" type="object | null" required>
      Política de cancelación aplicada, o `null` cuando no aplica ninguna.

      <Expandable title="propiedades">
        <ResponseField name="type" type="string" required>
          Tipo de política. Este objeto usa `PREPAYMENT` o
          `GUARANTEE_AUTHORIZATION`. Consulta
          [CancellationPolicyType](/getting-started/enums#cancellationpolicytype)
          para su significado.
        </ResponseField>

        <ResponseField name="amount" type="number" required>
          Importe de la política por comensal o por reserva, según `amount_type`,
          en la unidad más pequeña de la divisa.
        </ResponseField>

        <ResponseField name="amount_type" type="string" required>
          Cómo se aplica `amount`. Consulta
          [CancellationPolicyAmountType](/getting-started/enums#cancellationpolicyamounttype) para más información.
        </ResponseField>

        <ResponseField name="cancellation_fee_amount" type="number" required>
          Penalización total por cancelación en la unidad más pequeña de la divisa.
        </ResponseField>

        <ResponseField name="charged_amount" type="number | null" required>
          Importe cobrado por adelantado en la unidad más pequeña de la divisa, o
          `null` cuando todavía no se ha cobrado nada.
        </ResponseField>

        <ResponseField name="cancellation_notice_hours" type="number" required>
          Número de horas antes de la reserva a partir de las cuales empieza a
          aplicarse la penalización por cancelación.
        </ResponseField>

        <ResponseField name="currency" type="string" required>
          Código de divisa ISO 4217. Consulta
          [Currency](/getting-started/enums#currency) para más información.
        </ResponseField>
      </Expandable>
    </ResponseField>
  </Expandable>
</ResponseField>

### IDs de recurso

Los ID de experiencias, complementos, zonas y franjas horarias usan este formato:

```text theme={null}
{account_id}:{resource_type}:{source_id}
```

Cada segmento va en minúsculas. Los caracteres no alfanuméricos se normalizan a guiones bajos.

```text theme={null}
best_burger:experience:7
best_burger:add_on:12
best_burger:floor_plan_area:3
best_burger:time_slot:20_30
```

El ID de una franja horaria identifica la cuenta y la hora local del día. Usa los campos `date` y `floor_plan_area_id` del elemento cuando necesites el contexto completo de la reserva.

### NoAvailability

Lo usa `booking_no_availability_viewed`.

```js theme={null}
{
  availability: {
    outcome: "SHIFT_FULL",
    fallback_actions: ["CONTACT", "SEARCH_ALTERNATIVE_DATES"]
  },
  booking: {
    // Los mismos campos que BookingFunnel.booking.
  }
}
```

**Campos**

<ResponseField name="availability" type="object" required>
  Resultado que se muestra cuando no se encuentra disponibilidad.

  <Expandable title="propiedades">
    <ResponseField name="outcome" type="string" required>
      Motivo, en formato legible por máquina, de que la búsqueda no tenga
      disponibilidad. Consulta
      [AvailabilityOutcome](/getting-started/enums#availabilityoutcome) para los
      valores posibles y su significado.
    </ResponseField>

    <ResponseField name="fallback_actions" type="string[]" required>
      Alternativas que se ofrecen al visitante. Consulta
      [AvailabilityFallbackOption](/getting-started/enums#availabilityfallbackoption)
      para los valores posibles y su significado.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="booking" type="object" required>
  Instantánea de la reserva documentada en [BookingFunnel](#bookingfunnel).
</ResponseField>

### BookingViewItemList

Lo usa `booking_item_list_viewed`. Sigue el patrón `view_item_list` de ecommerce y se emite una vez cuando se muestra la vista del listado.

**Campos**

<ResponseField name="list_type" type="string" required>
  Tipo de listado que se muestra.

  | Valor                 | Significado                                             |
  | --------------------- | ------------------------------------------------------- |
  | `booking_experiences` | Experiencias o menús disponibles para reservar.         |
  | `booking_time_slots`  | Horas de reserva disponibles.                           |
  | `booking_add_ons`     | Productos opcionales que se pueden añadir a la reserva. |
</ResponseField>

<ResponseField name="items" type="object[]" required>
  Elementos que se muestran en el listado. Sus campos dependen de `list_type`.

  <Expandable title="elemento de booking_experiences">
    <ResponseField name="id" type="string" required>
      ID de la experiencia con espacio de nombres. Ejemplo: `"best_burger:experience:7"`.
    </ResponseField>

    <ResponseField name="price_per_ticket" type="number" required>
      Precio por ticket en la unidad más pequeña de la divisa.
    </ResponseField>

    <ResponseField name="currency" type="string" required>
      Código de divisa ISO 4217. Consulta [Currency](/getting-started/enums#currency) para más información.
    </ResponseField>

    <ResponseField name="is_time_limited" type="boolean" required>
      Indica si la experiencia tiene una hora de fin fija.
    </ResponseField>
  </Expandable>

  <Expandable title="elemento de booking_time_slots">
    <ResponseField name="id" type="string" required>
      ID de la franja horaria con espacio de nombres. Ejemplo: `"best_burger:time_slot:20_30"`.
    </ResponseField>

    <ResponseField name="date" type="string" required>
      Fecha de calendario ISO 8601 en formato `YYYY-MM-DD`.
    </ResponseField>

    <ResponseField name="time" type="string" required>
      Hora local del local en formato ISO 8601 `HH:mm:ss`.
    </ResponseField>

    <ResponseField name="floor_plan_area_id" type="string | null" required>
      ID de la zona de mesas con espacio de nombres, o `null` cuando no aplica ninguna zona.
    </ResponseField>
  </Expandable>

  <Expandable title="elemento de booking_add_ons">
    <ResponseField name="id" type="string" required>
      ID del complemento con espacio de nombres. Ejemplo: `"best_burger:add_on:12"`.
    </ResponseField>

    <ResponseField name="unit_price" type="number" required>
      Precio unitario en la unidad más pequeña de la divisa.
    </ResponseField>

    <ResponseField name="currency" type="string" required>
      Código de divisa ISO 4217. Consulta
      [Currency](/getting-started/enums#currency) para más información.
    </ResponseField>
  </Expandable>
</ResponseField>

<Tabs>
  <Tab title="Experiencias">
    ```js theme={null}
    {
      list_type: "booking_experiences",
      items: [
        {
          id: "best_burger:experience:7",
          price_per_ticket: 6500,
          currency: "EUR",
          is_time_limited: false
        }
      ]
    }
    ```
  </Tab>

  <Tab title="Franjas horarias">
    ```js theme={null}
    {
      list_type: "booking_time_slots",
      items: [
        {
          id: "best_burger:time_slot:20_30",
          date: "2026-07-25",
          time: "20:30:00",
          floor_plan_area_id: "best_burger:floor_plan_area:3"
        }
      ]
    }
    ```
  </Tab>

  <Tab title="Complementos">
    ```js theme={null}
    {
      list_type: "booking_add_ons",
      items: [
        {
          id: "best_burger:add_on:12",
          unit_price: 2500,
          currency: "EUR"
        }
      ]
    }
    ```
  </Tab>
</Tabs>

### BookingSelectItem

Lo usa `booking_item_selected`. Sigue el patrón `select_item` de ecommerce. Las formas de los elementos coinciden con [BookingViewItemList](#bookingviewitemlist); las experiencias seleccionadas incluyen además `tickets`, y los complementos seleccionados, `quantity`.

**Campos**

<ResponseField name="list_type" type="string" required>
  Tipo de elemento seleccionado.

  | Valor                 | Significado                             |
  | --------------------- | --------------------------------------- |
  | `booking_experiences` | Selección de una experiencia o un menú. |
  | `booking_time_slots`  | Selección de una hora de reserva.       |
  | `booking_add_ons`     | Selección de un complemento.            |
</ResponseField>

<ResponseField name="items" type="object[]" required>
  Elementos seleccionados. Sus campos dependen de `list_type`.

  <Expandable title="elemento de booking_experiences">
    <ResponseField name="id" type="string" required>
      ID de la experiencia con espacio de nombres.
    </ResponseField>

    <ResponseField name="price_per_ticket" type="number" required>
      Precio por ticket en la unidad más pequeña de la divisa.
    </ResponseField>

    <ResponseField name="currency" type="string" required>
      Código de divisa ISO 4217. Consulta [Currency](/getting-started/enums#currency) para más información.
    </ResponseField>

    <ResponseField name="is_time_limited" type="boolean" required>
      Indica si la experiencia tiene una hora de fin fija.
    </ResponseField>

    <ResponseField name="tickets" type="number" required>
      Número de tickets seleccionados.
    </ResponseField>
  </Expandable>

  <Expandable title="elemento de booking_time_slots">
    <ResponseField name="id" type="string" required>
      ID de la franja horaria con espacio de nombres.
    </ResponseField>

    <ResponseField name="date" type="string" required>
      Fecha de calendario ISO 8601 en formato `YYYY-MM-DD`.
    </ResponseField>

    <ResponseField name="time" type="string" required>
      Hora local del local en formato ISO 8601 `HH:mm:ss`.
    </ResponseField>

    <ResponseField name="floor_plan_area_id" type="string | null" required>
      ID de la zona de mesas con espacio de nombres, o `null` cuando no aplica ninguna zona.
    </ResponseField>
  </Expandable>

  <Expandable title="elemento de booking_add_ons">
    <ResponseField name="id" type="string" required>
      ID del complemento con espacio de nombres.
    </ResponseField>

    <ResponseField name="unit_price" type="number" required>
      Precio unitario en la unidad más pequeña de la divisa.
    </ResponseField>

    <ResponseField name="currency" type="string" required>
      Código de divisa ISO 4217. Consulta
      [Currency](/getting-started/enums#currency) para más información.
    </ResponseField>

    <ResponseField name="quantity" type="number" required>
      Número de unidades seleccionadas.
    </ResponseField>
  </Expandable>
</ResponseField>

<Tabs>
  <Tab title="Experiencia">
    ```js theme={null}
    {
      list_type: "booking_experiences",
      items: [
        {
          id: "best_burger:experience:7",
          price_per_ticket: 6500,
          currency: "EUR",
          is_time_limited: false,
          tickets: 2
        }
      ]
    }
    ```
  </Tab>

  <Tab title="Franja horaria">
    ```js theme={null}
    {
      list_type: "booking_time_slots",
      items: [
        {
          id: "best_burger:time_slot:20_30",
          date: "2026-07-25",
          time: "20:30:00",
          floor_plan_area_id: "best_burger:floor_plan_area:3"
        }
      ]
    }
    ```
  </Tab>

  <Tab title="Complemento">
    ```js theme={null}
    {
      list_type: "booking_add_ons",
      items: [
        {
          id: "best_burger:add_on:12",
          unit_price: 2500,
          currency: "EUR",
          quantity: 2
        }
      ]
    }
    ```
  </Tab>
</Tabs>

### BookingViewItemDetail

Lo usa `booking_item_detail_viewed`. Sigue el patrón `view_item` de ecommerce.

```js theme={null}
{
  type: "experience",
  list_type: "booking_experiences",
  item: {
    id: "best_burger:experience:7"
  }
}
```

**Campos**

<ResponseField name="type" type="string" required>
  Tipo de elemento que se ha abierto.

  | Valor             | Significado             |
  | ----------------- | ----------------------- |
  | `experience`      | Una experiencia o menú. |
  | `floor_plan_area` | Una zona de mesas.      |
</ResponseField>

<ResponseField name="list_type" type="string" required>
  Listado desde el que se abrió el detalle: `booking_experiences`,
  `booking_time_slots` o `booking_add_ons`. Consulta las definiciones en
  [BookingViewItemList](#bookingviewitemlist).
</ResponseField>

<ResponseField name="item" type="object" required>
  Elemento cuyo detalle se ha abierto.

  <Expandable title="propiedades">
    <ResponseField name="id" type="string" required>
      ID de recurso con espacio de nombres.
    </ResponseField>
  </Expandable>
</ResponseField>

### ActionTaken

Lo usa `action_taken`.

```js theme={null}
{
  category: "contact",
  option: "whatsapp"
}
```

**Campos**

<ResponseField name="category" type="string" required>
  Grupo al que pertenece la acción.

  | Valor                      | Significado                                                              |
  | -------------------------- | ------------------------------------------------------------------------ |
  | `contact`                  | El visitante contacta con el negocio.                                    |
  | `add_to_calendar`          | El visitante guarda una reserva en un calendario.                        |
  | `invite_guests`            | El visitante comparte una invitación a la reserva.                       |
  | `get_directions`           | El visitante abre las indicaciones para llegar al local.                 |
  | `recommend`                | El visitante recomienda el negocio.                                      |
  | `share_experience`         | El visitante comparte o valora la experiencia.                           |
  | `update_booking`           | El visitante abre el flujo para modificar una reserva.                   |
  | `cancel_booking`           | El visitante abre el flujo para cancelar una reserva.                    |
  | `add_to_contacts`          | El visitante guarda los datos de contacto del negocio.                   |
  | `visit_website`            | El visitante abre la web del negocio.                                    |
  | `no_availability_fallback` | El visitante elige una alternativa tras una búsqueda sin disponibilidad. |
</ResponseField>

<ResponseField name="option" type="string" required>
  Elección concreta dentro de la categoría.

  | Valor                       | Significado                                                          |
  | --------------------------- | -------------------------------------------------------------------- |
  | `open`                      | Abre un menú, un modal o un selector antes de una elección concreta. |
  | `click`                     | Ejecuta una acción directa, sin submenú.                             |
  | `phone`                     | Usa una llamada de teléfono.                                         |
  | `email`                     | Usa el correo electrónico.                                           |
  | `whatsapp`                  | Usa WhatsApp.                                                        |
  | `sms`                       | Usa SMS.                                                             |
  | `instagram`                 | Usa Instagram.                                                       |
  | `facebook`                  | Usa Facebook.                                                        |
  | `google`                    | Usa Google.                                                          |
  | `copy_link`                 | Copia un enlace al portapapeles.                                     |
  | `share`                     | Abre la interfaz de compartir nativa del dispositivo.                |
  | `copy_tag`                  | Copia la etiqueta del negocio al portapapeles.                       |
  | `copy_hashtags`             | Copia los hashtags sugeridos al portapapeles.                        |
  | `copy_sticker`              | Copia el sticker de la historia al portapapeles.                     |
  | `open_instagram`            | Abre Instagram para publicar un post o una historia.                 |
  | `google_calendar`           | Añade la reserva a Google Calendar.                                  |
  | `apple_calendar`            | Añade la reserva al calendario de Apple.                             |
  | `outlook_calendar`          | Añade la reserva al calendario de escritorio de Outlook.             |
  | `outlook_com`               | Añade la reserva a Outlook.com.                                      |
  | `venue_address`             | Abre las indicaciones a la dirección del local.                      |
  | `nearest_parking`           | Abre las indicaciones al aparcamiento más cercano.                   |
  | `contact`                   | Contacta con el negocio tras una búsqueda sin disponibilidad.        |
  | `request_booking`           | Solicita una reserva para que el negocio la confirme.                |
  | `join_wait_list`            | Se apunta a la lista de espera del negocio.                          |
  | `search_alternative_dates`  | Busca disponibilidad en otras fechas.                                |
  | `search_alternative_venues` | Busca disponibilidad en otros locales del grupo.                     |
  | `update_search`             | Cambia la búsqueda actual.                                           |
</ResponseField>

<Note>
  **Un contacto desde el menú emite dos eventos, no uno.** Al abrir el menú de
  contacto llega `option: "open"`, y al elegir el canal llega el canal —
  `"whatsapp"`, `"phone"` o `"email"`—, los dos con `category: "contact"`. Donde
  los canales se muestran directos, sin menú, solo llega el segundo.

  Así que para contar contactos, filtra por `option` y no solo por `category`.
  Las conversiones no se ven afectadas: `"open"` y `"click"` nunca las disparan
  ([Mapeo de eventos](/es/widget/connect-mappings#datos-ga4-de-las-acciones)).
</Note>

### CustomerIdentified

Lo usa `customer_identified`.

```js theme={null}
{
  method: "form",
  customer: {
    email: "b4c9a289323b21a01c3e940f150eb9b8c542587f1abfd8f0e1cc1ffc5e475514",
    phoneE164: "8c3b8b4a7db6e8d8b2f3f0d3a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0",
    phoneMsisdn: "14976e7970d2191d37cb8853db2d372d671594e432cae1f6602668060303222a"
  }
}
```

**Campos**

<ResponseField name="method" type="string" required>
  Cómo se ha identificado al cliente.

  | Valor         | Significado                                          |
  | ------------- | ---------------------------------------------------- |
  | `form`        | El cliente envió el formulario de datos.             |
  | `remember_me` | El widget restauró los datos recordados del cliente. |
</ResponseField>

<ResponseField name="customer" type="object" required>
  Cliente identificado. Los valores de texto personales se normalizan quitando
  los espacios del principio y del final y pasándolos a minúsculas antes de
  hashearlos.

  <Expandable title="propiedades">
    <ResponseField name="email" type="string | null" required>
      Hash SHA-256 del correo normalizado, representado como 64 caracteres
      hexadecimales en minúsculas, o `null` si no está presente.
    </ResponseField>

    <ResponseField name="phoneE164" type="string | null" required>
      Hash SHA-256 del número de teléfono en formato
      [E.164](https://en.wikipedia.org/wiki/E.164) (con el `+` inicial),
      representado como 64 caracteres hexadecimales en minúsculas, o `null` si no
      está presente.
    </ResponseField>

    <ResponseField name="phoneMsisdn" type="string | null" required>
      Hash SHA-256 del mismo número de teléfono en formato
      [MSISDN](https://en.wikipedia.org/wiki/MSISDN) (los mismos dígitos, sin el
      `+`), o `null` si no está presente. Meta necesita este formato para su cruce
      de datos; el resto de destinos usan `phoneE164`.
    </ResponseField>
  </Expandable>
</ResponseField>

## Enviar eventos concretos a tu data layer

Puedes reenviar solo los eventos que le importan a tu web:

```js theme={null}
const restooEvents = [
  "booking_start_submitted",
  "booking_details_form_submitted",
  "booking_created",
];

restooEvents.forEach((name) => {
  window.addEventListener(`restoo:${name}`, (event) => {
    window.dataLayer = window.dataLayer || [];
    window.dataLayer.push({
      event: `restoo_${name}`,
      restoo: event.detail,
    });
  });
});
```

Para las correspondencias automáticas con las plataformas de analítica admitidas, usa [Restoo Connect](/es/widget/connect).

## Siguientes pasos

<CardGroup cols={2}>
  <Card title="Mapeo de eventos" icon="table" href="/es/widget/connect-mappings">
    En qué se convierte cada uno de estos eventos en GA4, Google Ads, Meta,
    TikTok, ChatGPT Ads y GTM.
  </Card>

  <Card title="Consentimiento" icon="shield-check" href="/es/widget/consent">
    Qué necesita permiso y qué no, y por qué la identidad del cliente va aparte.
  </Card>
</CardGroup>
