Skip to content

Modelos de integración de canal

Este documento describe los cuatro modelos contractuales de integración que beTickets soporta para canales de venta de terceros. Cada canal tiene exactamente un modelo configurado por el equipo de beTickets en el dashboard de administración.


Resumen

ModeloNombre técnicoFrontend compradorQuién cobraWidgetEndpoint de pago
Aportal_onlyPortal beTickets (branding del canal)beTickets (Redsys)/portal/{slug}/{lang}/checkout
Bportal_external_paymentPortal beTickets (branding del canal)Canal (TPV propio)POST /confirm (canal→beTickets)
Cwidget_betickets_paymentSite del canal (widget) → redirect a portalbeTickets (Redsys)/portal/{slug}/{lang}/checkout?order_token=…
Dwidget_external_paymentSite del canal (widget embebido)Canal (TPV propio)POST /confirm (canal→beTickets)

Los modelos se organizan en dos dimensiones:

  • Frontend: portal beTickets vs widget embebido en el site del canal
  • Cobro: beTickets gestiona el pago (Redsys) vs el canal cobra con su TPV

Modelo A — Portal white-label, cobro beTickets (portal_only)

El canal utiliza el portal de beTickets con su propio branding (logo, colores, dominio via CNAME). beTickets procesa el cobro a través de Redsys.

Flujo de compra

Comprador → portal.canal.com/{slug}/{lang}/events
→ Selecciona sesión y asientos
→ Checkout nativo del portal: nombre, email, datos de pago
→ Pasarela Redsys (gestionada por beTickets)
→ Confirmación: asientos vendidos, tickets enviados

Requisitos técnicos

  • CNAME del dominio del canal apuntando a beTickets
  • Logo, colores, favicon configurados en el dashboard
  • No requiere widget_key ni integración técnica adicional

Modelo B — Portal white-label, cobro del canal (portal_external_payment)

El canal utiliza el portal de beTickets con su propio branding. El cobro lo gestiona el canal con su TPV. Cuando el pago se confirma, el canal notifica a beTickets.

Flujo de compra

Comprador → portal.canal.com/{slug}/{lang}/events
→ Selecciona sesión y asientos en el portal beTickets
→ Checkout del portal: nombre, email
→ Canal procesa el pago con su pasarela (server-side)
→ Canal notifica a beTickets:
    POST https://api.betickets.com/api/sales-channel/v1/{slug}/{lang}/orders/{orderToken}/confirm
    Authorization: Bearer {access_token}
    { "transaction_id": "ext_123", "amount": 125.50, "payment_method": "card" }
→ beTickets: asientos vendidos, tickets enviados al comprador

Requisitos técnicos

  • CNAME del dominio del canal apuntando a beTickets
  • widget_key generada en el dashboard (necesaria para autenticación B2B)
  • Implementación server-side del endpoint confirm
  • No se permite: redirigir al portal de beTickets para pago (lo maneja el canal)

Autenticación B2B

  1. POST /api/sales-channel/v1/auth/token con sales_channel_slug + widget_key → Bearer token
  2. Usar Bearer token en la llamada de confirmación

⚠️ La llamada a confirm siempre debe hacerse desde el servidor del canal, nunca desde el navegador del comprador.


Modelo C — Widget + cobro beTickets (widget_betickets_payment)

El canal embebe el widget en su site para la selección de asientos. El pago lo procesa beTickets a través del portal, al que el widget redirige automáticamente.

Flujo de compra

Comprador → site del canal (con widget embebido)
→ Widget: selecciona asientos (crea orden B2B)
→ Widget: botón "Ir al pago" → redirect a:
    {portal_checkout_base_url}/{slug}/{lang}/checkout?order_token={token}
→ Portal beTickets con branding del canal
→ Comprador introduce datos y paga (Redsys)
→ Confirmación: asientos vendidos, tickets enviados

Requisitos técnicos

  • widget_key generada en el dashboard
  • Integración del widget en el site del canal (ver widget quickstart)
  • El widget se autoconfigura para redirect; no pasar checkoutMode ni checkoutBaseUrl
  • No se permite: llamar a confirm (el pago lo cierra beTickets internamente)

📘 Walkthrough completo: para una guía paso a paso de integración del Modelo C (configuración del canal, embed, aislamiento de CSS, tracking, checklist de producción y troubleshooting), ver Tutorial · Modelo C.


Modelo D — Widget + cobro del canal (widget_external_payment)

El canal embebe el widget en su site. El canal procesa el cobro con su propia pasarela y notifica a beTickets del resultado. beTickets no envía email de entradas — el canal es responsable del envío (sus propios bonos, billetes de tren, entradas PDF, etc.).

Flujo de compra

Comprador → site del canal (con widget embebido)
→ Widget: selecciona asientos y arma carrito
→ Widget emite onOrderUpdate(order) con order_token y total
→ Canal habilita su botón de pago nativo
→ Canal recoge datos del comprador (nombre, email, teléfono)
→ Canal procesa pago con su pasarela (server-side)
→ Canal notifica a beTickets (server-to-server):
    POST /api/sales-channel/v1/{slug}/{lang}/orders/{orderToken}/confirm
    Authorization: Bearer {access_token}
    {
      "transaction_id": "tpv_ext_123",
      "amount": 125.50,
      "payment_method": "card",
      "name": "Ana",
      "surname": "García",
      "email": "ana@example.com",
      "phone": "600000000"
    }
→ beTickets: asientos → sold, genera tickets PDF, responde con URLs firmadas (7 días):
    {
      "order_id": 123,
      "status": "completed",
      "ticket_pdf_urls": [
        { "order_item_id": 1, "ticket_code": "TK-XXXX", "url": "https://s3.../ticket.pdf" }
      ]
    }
→ Canal descarga los PDFs e incluye las entradas en su propio email al comprador
→ Canal llama instance.notifyPaymentComplete() para limpiar el widget

Cuerpo de la petición confirm (modelo D)

CampoTipoRequeridoDescripción
transaction_idstringIdentificador de la transacción en la pasarela del canal
amountnumberImporte cobrado; debe coincidir con order.total_amount (±0.01 €)
payment_methodstringNoMétodo de pago (ej. "card", "bizum")
namestringNombre del comprador
surnamestringApellidos del comprador
emailstringEmail del comprador (beTickets crea o actualiza el Customer)
phonestringNoTeléfono del comprador
accept_marketingbooleanNoConsentimiento de marketing

Respuesta confirm (modelo D)

json
{
  "success": true,
  "message": "Pago confirmado correctamente",
  "data": {
    "order_id": 123,
    "status": "completed",
    "ticket_pdf_urls": [
      {
        "order_item_id": 45,
        "ticket_code": "TK-ABCD-1234",
        "url": "https://tickets-bucket.s3.eu-west-1.amazonaws.com/...?X-Amz-Expires=604800"
      }
    ]
  }
}

Las URLs de ticket_pdf_urls son presignadas con validez de 7 días. El canal debe descargar los PDFs e incluirlos en su propio email al comprador. beTickets no envía ningún email en este modelo.

Requisitos técnicos

  • widget_key generada en el dashboard
  • Integración del widget en el site del canal (ver widget quickstart)
  • Implementación server-side del endpoint confirm con los datos del comprador
  • No se permite: redirigir al portal de beTickets para el pago

Autenticación B2B

  1. POST /api/sales-channel/v1/auth/token con sales_channel_slug + widget_key → Bearer token
  2. Usar Bearer token en la llamada de confirmación

⚠️ La llamada a confirm siempre debe hacerse desde el servidor del canal, nunca desde el navegador del comprador.


Capacidades por modelo

Endpoint / CapacidadModelo AModelo BModelo CModelo D
POST /portal/{slug}/{lang}/checkout❌ 403
POST /sales-channel/v1/.../orders (crear orden B2B)❌ 403❌ 403
POST /sales-channel/v1/.../orders/{token}/confirm❌ 403❌ 403
GET /sales-channel/v1/{slug}/config
Widget embebido
Botón checkout en widget❌ (oculto)

Shadow mode: con enforcement_enabled=false, los endpoints inválidos para el modelo generan un log de warning sin rechazar la petición. Permite detectar canales mal configurados antes de activar el enforcement estricto.


Configurar el modelo en el dashboard

  1. Ir a Administración → Canales de venta → [canal] → Configuración
  2. En la sección "Modelo de integración", seleccionar el modelo correspondiente al acuerdo contractual
  3. Guardar los cambios

El modelo se aplica a todos los eventos del canal. No es posible override por evento en v1.


Leer el modelo desde la API

El endpoint GET /api/sales-channel/v1/{slug}/config devuelve los campos de integración:

json
{
  "data": {
    "channel_slug": "mi-canal",
    "integration_mode": "widget_external_payment",
    "payment_handler": "channel",
    "allows_widget": true,
    "requires_external_payment_callback": true,
    "redirects_to_betickets_checkout": false,
    "portal_checkout_base_url": "https://tickets.bticketing.com"
  }
}

El widget consume este endpoint al arrancar y se autoconfigura según integration_mode. El integrador no debe sobreescribir checkoutMode ni checkoutBaseUrl.


Migraciones de datos

Todos los canales existentes sin configuración de integration_mode tienen asignado el modelo A por defecto. Para reclasificar canales, usar el comando de auditoría:

bash
php artisan sales-channels:audit-integration-modes
php artisan sales-channels:audit-integration-modes --export  # genera CSV

Referencias

beTickets — Plataforma de ticketing