Skip to content

Quickstart Widget

El widget es aplicable únicamente a los modelos C y D de integración. En los modelos A y B el comprador accede al portal de beTickets directamente.

Modelo¿Usa widget?Botón checkout en widget
A portal_only
B portal_external_payment
C widget_betickets_payment✅ Visible (redirige al portal)
D widget_external_payment❌ Oculto (canal gestiona pago)

Entornos

EntornoWidget IIFEAPI
Producciónhttps://widget.bticketing.com/v1/widget.iife.jshttps://api.bticketing.com/api
Preproducciónhttps://widget-pre.betickets.io/v1/widget.iife.jshttps://api-pre.betickets.io/api

Inicialización explícita obligatoria

El widget no se auto-inicializa a partir de atributos data-bt-widget. Siempre debes llamar a BeTickets.init() explícitamente después de cargar el script.


Modelo C — Widget con cobro beTickets

El widget muestra el botón "Ir al pago" de forma nativa. Al pulsarlo, el comprador es redirigido al portal de beTickets para completar el pago. El canal no implementa ningún flujo de cobro.

📘 Para una guía paso a paso completa (configuración del canal, aislamiento de CSS, tracking, checklist de producción), ver el Tutorial · Modelo C.

html
<div id="bt-widget"></div>

<script src="https://widget.bticketing.com/v1/widget.iife.js"></script>
<script>
  BeTickets.init({
    container:   '#bt-widget',
    channelSlug: 'sala-el-sol',
    sessionId:   83,
    apiKey:      'wk_xxxx',
    lang:        'es',
  });
  // El widget consulta /config, detecta widget_betickets_payment
  // y configura automáticamente el botón y la URL de redirect.
  // No es necesario pasar checkoutMode ni checkoutBaseUrl.
</script>

Modelo D — Widget con cobro externo

El widget no muestra botón de checkout. El canal escucha onOrderUpdate para saber cuándo hay items en el carrito, habilita su propio botón de pago y, tras cobrar, notifica a beTickets vía POST /confirm.

beTickets no envía email de entradas en este modelo. La respuesta de /confirm incluye URLs firmadas de los tickets PDF (validez 7 días) para que el canal los adjunte en su propio correo.

html
<div id="bt-widget"></div>
<button id="pay-btn" disabled>Pagar con mi pasarela</button>
<div id="pay-status"></div>

<script src="https://widget.bticketing.com/v1/widget.iife.js"></script>
<script>
  const instance = BeTickets.init({
    container:   '#bt-widget',
    channelSlug: 'liga-deportiva',
    sessionId:   94,
    apiKey:      'wk_xxxx',
    lang:        'es',
    onOrderUpdate: (order) => {
      const items = (order?.events ?? [])
        .flatMap(ev => (ev.sessions ?? []).flatMap(s => s.items ?? []));
      document.getElementById('pay-btn').disabled = items.length === 0;
    },
    onOrderComplete: (order) => {
      // Disparado por instance.notifyPaymentComplete() tras confirmar
      document.getElementById('pay-status').textContent = '✓ Compra completada';
    },
  });

  document.getElementById('pay-btn').addEventListener('click', async () => {
    const order = instance.getOrder();
    if (!order) return;

    // 1. Tu servidor cobra con su pasarela y llama server-to-server a beTickets:
    //    POST /api/sales-channel/v1/{slug}/{lang}/orders/{token}/confirm
    //    { transaction_id, amount, payment_method, name, surname, email, phone }
    //
    // 2. beTickets responde con ticket_pdf_urls (URLs firmadas, 7 días de validez)
    //    El canal adjunta esos PDFs en su propio email al comprador.
    const result = await fetch('/api/tu-servidor/confirmar-pago', {
      method: 'POST',
      body: JSON.stringify({
        order_token: order.order_token,
        amount:      order.total_amount,
        // nombre, email, teléfono del comprador (recogidos por el canal)
      }),
    }).then(r => r.json());

    if (result.ok) {
      // 3. Avisa al widget: limpia el carrito y dispara onOrderComplete
      instance.notifyPaymentComplete();
    }
  });
</script>

Server-to-server

La llamada a POST /confirm siempre debe hacerse desde el servidor del canal, nunca desde el navegador del comprador. Ver Confirmación de pago.

Cambio de sesión (fecha/evento)

Al llamar a destroy() + init() con un sessionId diferente, si existía una orden de otra sesión en localStorage, el widget la cancela automáticamente en el backend antes de cargar la nueva sesión. No es necesario gestionar esta limpieza manualmente.


Una instancia por página

Singleton

El widget expone un cliente HTTP compartido (_accessToken, _client) a nivel de módulo. Si necesitas mostrar dos sesiones en la misma página, destruye la instancia anterior antes de crear una nueva:

js
// ✅ Correcto
let widgetInstance = BeTickets.init({ container: '#widget', sessionId: 94, ... });

// Al cambiar de sesión:
widgetInstance.destroy();
widgetInstance = BeTickets.init({ container: '#widget', sessionId: 93, ... });

// ❌ Incorrecto — dos instancias simultáneas con el mismo canal
BeTickets.init({ container: '#widget-a', sessionId: 94, ... });
BeTickets.init({ container: '#widget-b', sessionId: 93, ... }); // rompe la auth de la primera

API de instancia

ts
const instance = BeTickets.init(config);
Método / PropiedadDescripción
instance.getOrder()Devuelve la orden activa o null
instance.startCheckout()Lanza el checkout manualmente. Modelo D: emite console.warn y no redirige
instance.notifyPaymentComplete(order?)Modelo D: avisa al widget de pago externo completado → dispara onOrderComplete + limpia carrito
instance.destroy()Desmonta el widget y libera recursos
instance.policy{ integrationMode, paymentHandler } — disponible tras la carga asíncrona de /config

beTickets — Plataforma de ticketing