Flujo API (canales)
Guía del contrato B2B autenticado para integradores externos.
Prerequisito: antes de integrar, confirma qué modelo de integración tiene configurado el canal (A, B, C o D). Los endpoints disponibles y las restricciones de pago dependen del modelo. Solo los modelos B, C y D requieren autenticación B2B.
Base URL
- Producción:
https://api.bticketing.com/api - Preproducción API:
https://api-pre.betickets.io/api - Preproducción Widget:
https://widget-pre.betickets.io - Prefijo API de canales:
/sales-channel/v1
1) Autenticación
Único endpoint público. Intercambia sales_channel_slug + widget_key por un Bearer token Sanctum.
POST /sales-channel/v1/auth/token
Content-Type: application/json
{
"sales_channel_slug": "teatro-calderon",
"widget_key": "wk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}Respuesta:
{
"success": true,
"data": {
"access_token": "1|abc...",
"token_type": "Bearer",
"sales_channel_slug": "teatro-calderon"
}
}TIP
El token anterior se revoca automáticamente al solicitar uno nuevo. Guarda siempre el token más reciente.
Todos los endpoints siguientes requieren:
httpAuthorization: Bearer {access_token}
2) Configuración del canal
GET /sales-channel/v1/{salesChannelSlug}/configDevuelve branding y modelo de integración del canal. El widget consume este endpoint al arrancar para autoconfigurarse.
Campos relevantes de la respuesta:
| Campo | Descripción |
|---|---|
integration_mode | Modelo contractual: portal_only, portal_external_payment, widget_betickets_payment, widget_external_payment |
allows_widget | true si el canal puede usar el widget embebido (modelos C y D) |
checkout_url | URL del checkout externo del canal (solo modelo B) |
portal_checkout_base_url | URL base del portal de beTickets al que redirige el widget (modelo C) |
requires_external_payment_callback | true si el canal debe llamar a /confirm tras cobrar (modelos B y D) |
3) Catálogo (eventos y sesiones)
GET /sales-channel/v1/{salesChannelSlug}/{lang}/events
GET /sales-channel/v1/{salesChannelSlug}/{lang}/events/{eventId}
GET /sales-channel/v1/{salesChannelSlug}/{lang}/events/{eventId}/sessions
GET /sales-channel/v1/{salesChannelSlug}/{lang}/events/{eventId}/sessions/{sessionId}
GET /sales-channel/v1/{salesChannelSlug}/{lang}/events/{eventId}/mapsNotas de payload:
GET .../eventsdevuelve payload simplificado: sinfeesnimanual_promotions.sessionsincluyeid+start_datetime.GET .../events/{eventId}/sessions/{sessionId}devuelve el detalle de sesión saneado:- sin
data.sales_channel - sin
session.venue - sin
session.start_date/session.end_date - sin
session.fees - sin
created_at/updated_atenelements.seats[].rates[].meta
- sin
4) Carrito / orden
POST /sales-channel/v1/{salesChannelSlug}/{lang}/orders
GET /sales-channel/v1/{salesChannelSlug}/{lang}/orders/{orderToken}
DELETE /sales-channel/v1/{salesChannelSlug}/{lang}/orders/{orderToken}POST .../orders:
order_tokenes opcional: si no se envía, el backend genera un UUID automáticamente.- Campos requeridos:
session_seat_id,rate_id.
Gestión de items
POST /sales-channel/v1/{salesChannelSlug}/{lang}/orders/{orderToken}/items
DELETE /sales-channel/v1/{salesChannelSlug}/{lang}/orders/{orderToken}/items/{itemId}
# Bulk
POST /sales-channel/v1/{salesChannelSlug}/{lang}/orders/{orderToken}/items-bulk
DELETE /sales-channel/v1/{salesChannelSlug}/{lang}/orders/{orderToken}/items/bulk
# Zonas no numeradas
POST /sales-channel/v1/{salesChannelSlug}/{lang}/orders/{orderToken}/items/sector
# Cambio de tarifa
PUT /sales-channel/v1/{salesChannelSlug}/{lang}/orders/{orderToken}/items/change-rate5) Descuentos
POST /sales-channel/v1/{salesChannelSlug}/{lang}/orders/{orderToken}/apply-voucher
DELETE /sales-channel/v1/{salesChannelSlug}/{lang}/orders/{orderToken}/vouchers/{voucherCode}6) Confirmación de pago (Modelos B y D)
El canal cobra con su pasarela y notifica el resultado a beTickets desde su servidor:
POST /sales-channel/v1/{salesChannelSlug}/{lang}/orders/{orderToken}/confirm
Authorization: Bearer {access_token}
Content-Type: application/json
{
"transaction_id": "ext_12345",
"amount": 125.50,
"payment_method": "card",
"name": "Ana",
"surname": "García",
"email": "ana@ejemplo.com",
"phone": "612345678"
}WARNING
name, surname y email son obligatorios — beTickets los usa para crear el registro del comprador y enviar las entradas.
Ver Flujo de pago — Confirmación para validaciones, idempotencia y errores.
6b) Consulta de orden (sin autenticación)
Endpoint público que el canal puede usar desde su página de checkout (Modelo B) para mostrar el resumen de la orden al comprador:
GET /portal/{salesChannelSlug}/{lang}/orders/{orderToken}No requiere Bearer token. Devuelve la estructura completa de la orden (events, sessions, items, total_amount, expires_at).
7) Informe de ventas
El canal de venta autenticado puede consultar sus propias ventas realizadas.
GUÍA PASO A PASO
Si eres un nuevo canal de ventas, ve directo a la Guía de integración: informe de ventas. Aquí tienes la referencia técnica del endpoint.
GET /sales-channel/v1/{salesChannelSlug}/{lang}/reports/salesParámetros de consulta (query string)
| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
event_id | integer | No | Filtrar por un evento concreto |
event_ids[] | array | No | Filtrar por varios eventos |
date_from | string (Y-m-d) | No | Fecha inicial del rango |
date_to | string (Y-m-d) | No | Fecha final del rango |
WARNING
Si se proporcionan date_from y date_to, la diferencia entre ambas no puede superar los 90 días.
Respuesta
{
"status": 200,
"success": true,
"data": {
"data": [
{
"id": 123,
"order_reference": "ABC-123",
"type": "purchase",
"datetime": "2025-04-01T14:30:00+00:00",
"customer_name": "Juan Pérez",
"customer_email": "juan@ejemplo.com",
"event_name": "Concierto de Rock",
"session_datetime": "2025-05-15T20:00:00+00:00",
"tickets": 2,
"base_amount": 100.00,
"discount_amount": -10.00,
"fee_amount": 5.00,
"payment_method": "card",
"total_amount": 95.00,
"currency": "EUR",
"status": "completed"
}
],
"summary": {
"transactions": 50,
"purchases": 40,
"refunds": 5,
"reservations": 5,
"tickets": 120,
"base_amount": 3000.00,
"discount_amount": -200.00,
"fee_amount": 150.00,
"total_amount": 2950.00,
"refund_amount": 250.00,
"net_amount": 2700.00,
"currency": "EUR"
}
},
"message": "Sales report retrieved successfully"
}Descripción de campos
| Campo | Descripción |
|---|---|
data[].type | Tipo de orden: purchase, refund, reservation |
data[].datetime | Fecha/hora ISO 8601 de creación de la orden |
data[].tickets | Número de entradas en la orden |
data[].base_amount | Suma del precio base de las entradas |
data[].discount_amount | Suma de descuentos aplicados (valor negativo) |
data[].fee_amount | Suma de gastos de gestión |
data[].total_amount | Importe total de la orden |
data[].status | Estado de la orden: completed, cancelled |
summary.transactions | Total de transacciones en el resultado |
summary.net_amount | Importe neto (purchases + refunds) |
summary.refund_amount | Importe total devuelto (en valor absoluto) |
Ejemplo rápido (curl)
Producción:
# 1. Obtener token
TOKEN=$(curl -s -X POST "https://api.bticketing.com/api/sales-channel/v1/auth/token" \
-H "Content-Type: application/json" \
-d '{"sales_channel_slug":"teatro-calderon","widget_key":"wk_xxxx"}' \
| jq -r '.data.access_token')
# 2. Config del canal
curl "https://api.bticketing.com/api/sales-channel/v1/teatro-calderon/config" \
-H "Authorization: Bearer $TOKEN"
# 3. Listar eventos
curl "https://api.bticketing.com/api/sales-channel/v1/teatro-calderon/es/events" \
-H "Authorization: Bearer $TOKEN"
# 4. Crear orden (sin order_token — backend lo genera)
curl -X POST "https://api.bticketing.com/api/sales-channel/v1/teatro-calderon/es/orders" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"session_seat_id":456,"rate_id":1}'Preproducción:
curl -X POST "https://api-pre.betickets.io/api/sales-channel/v1/auth/token" \
-H "Content-Type: application/json" \
-d '{"sales_channel_slug":"teatro-calderon","widget_key":"wk_xxxx"}'
curl "https://api-pre.betickets.io/api/sales-channel/v1/teatro-calderon/es/events" \
-H "Authorization: Bearer {{access_token}}"