Monetiza tu canal
a tu manera
Conecta Stripe, PayPal, Patreon o cualquier proveedor de pago. Nosotros gestionamos los códigos de acceso y el envío de correos. Te quedas con el 100% de los ingresos.
Sin código
Proveedores de pago compatibles
Elige el proveedor de pago que ya utilizas. Nos conectamos a él, generamos códigos de acceso automáticamente y enviamos a tus clientes su enlace personal por correo electrónico.
Pago directo — alojamos una página de pago para ti
Stripe
Acepta tarjetas, Apple Pay, Google Pay. Creamos sesiones de Stripe Checkout con tu clave API.
Pago alojadoRevolut Business
Acepta pagos mediante Revolut checkout. Configuración rápida, compatible con múltiples divisas.
Pago alojadoPayPal
Acepta pagos con PayPal. Los compradores pagan con su cuenta de PayPal o tarjeta de crédito.
Pago alojadoPlataformas de creadores — ellos gestionan el pago, nosotros gestionamos el acceso
Patreon
Los patrocinadores obtienen acceso automáticamente cuando se suscriben a tu nivel mínimo.
Gumroad
Vende el acceso como un producto de Gumroad. Los compradores reciben su enlace tras la compra.
LemonSqueezy
Vende acceso a través de tu tienda LemonSqueezy. Gestiona impuestos y pagos.
Ko-fi
Los seguidores que te compren un "café" o se unan a tu membresía obtienen acceso al canal.
Buy Me a Coffee
Los seguidores y miembros reciben automáticamente acceso a tu canal.
Te quedas con el 100% de los ingresos. Nunca tocamos tu dinero. Los pagos van directamente a tu cuenta en el proveedor que elijas. Solo generamos los códigos de acceso y enviamos el enlace por correo.
Configuración
Conecta tu proveedor
Inicia sesión, elige tu proveedor de pago, introduce tus credenciales API y te damos un enlace de pago (para Stripe/Revolut/PayPal) o una URL de webhook (para Patreon/Gumroad/etc.).
Inicia sesión abajo
Usa la misma cuenta de Apple que utilizas en la app My TV Channel.
Elige proveedor e introduce claves
Selecciona tu proveedor de pago e introduce tu clave API o secreto de webhook. Establece precio y duración.
Comparte tu enlace
Obtén un enlace de pago para compartir con tu audiencia, o pega la URL de webhook en la configuración de tu proveedor.
Conecta tu proveedor de pago
Inicia sesión con la misma cuenta de Apple que usas en la app.
Dónde encontrar tu clave API de Stripe: Ve al panel de Stripe → Developers → API keys → copia tu Secret key (empieza con sk_live_).
Lo que recibirán tus clientes
Después de un pago exitoso, tu cliente recibe un correo electrónico con su enlace de acceso personal:
Tu acceso está listo
Gracias por tu compra. Ya tienes acceso a Nombre de tu canal.
Ver ahoraEste enlace es personal. Te da 30 días de acceso.
Descripción general
Cómo funciona
Tú gestionas el pago. Nosotros gestionamos el acceso. Cuando un cliente te paga (a través de tu sitio web, Stripe, Patreon o cualquier otro método), tu servidor llama a nuestra API para generar un código de acceso único. Tú le das ese código a tu cliente como enlace.
El cliente te paga
En tu sitio web, Patreon o cualquier sistema de pago que elijas.
Tu servidor llama a nuestra API
Genera un código de suscriptor con la caducidad y límites que desees.
El cliente recibe un enlace
Como https://tu-canal.localtvbroadcast.com/?subscriber=ABC2DEF
El cliente ve el canal
Se abre en la app (con acceso concedido) o se reproduce directamente en el navegador web.
Te quedas con el 100% de los ingresos. No procesamos pagos ni cobramos comisión. Los códigos de suscriptor simplemente otorgan acceso a tu canal dentro de My TV Channel.
Primeros pasos
Autenticación
Todas las llamadas a la API del publicador requieren un token JWT. Obtén uno iniciando sesión con tu cuenta de My TV Channel:
# Inicia sesión para obtener tu token JWT
curl -X POST https://localtvbroadcast.com/api/mytvchannel/auth/login.php \
-H "Content-Type: application/json" \
-d '{
"email": "tu@ejemplo.com",
"password": "tu-contraseña"
}'
La respuesta incluye un campo token. Úsalo en todas las solicitudes posteriores:
Authorization: Bearer TU_TOKEN_JWT
Mantén tu token seguro. Almacénalo como una variable de entorno del servidor. Nunca lo expongas en código del lado del cliente ni en repositorios públicos.
URL base
Todos los endpoints de la API usan la siguiente URL base:
https://localtvbroadcast.com/api/mytvchannel/subscriber-codes/
Referencia de la API
Generar un código
/subscriber-codes/generate.php
Crea un nuevo código de acceso de suscriptor para tu canal. Requiere autenticación y propiedad del canal.
Cuerpo de la solicitud
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
| channel_id | integer | requerido | El ID de tu canal |
| expires_at | string | requerido | Fecha ISO 8601 en la que el código deja de aceptar nuevos canjes |
| label | string | opcional | Etiqueta interna (ej. "Pase mensual VIP") |
| price | number | opcional | Tu precio (solo metadatos, no procesamos el pago) |
| currency | string | opcional | Código de moneda ISO 4217 (predeterminado: USD) |
| max_redemptions | integer | opcional | Usos máximos. null = ilimitado |
| access_duration_days | integer | opcional | Días de acceso por canje. null = acceso hasta expires_at |
Ejemplo
curl -X POST https://localtvbroadcast.com/api/mytvchannel/subscriber-codes/generate.php \
-H "Authorization: Bearer TU_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"channel_id": 42,
"expires_at": "2026-12-31T23:59:59Z",
"label": "Pase mensual - Marzo",
"price": 9.99,
"currency": "USD",
"max_redemptions": 1,
"access_duration_days": 30
}'
Respuesta
{
"success": true,
"message": "Subscriber code generated",
"data": {
"id": 1,
"code": "A3F7K2N",
"url": "https://tu-canal.localtvbroadcast.com/?subscriber=A3F7K2N",
"channel_id": 42,
"label": "Pase mensual - Marzo",
"price": 9.99,
"currency": "USD",
"max_redemptions": 1,
"expires_at": "2026-12-31T23:59:59+00:00",
"access_duration_days": 30
}
}
Códigos de un solo uso vs. multiuso: Establece max_redemptions: 1 para un código único por cliente. Establécelo en null para un código promocional compartido que cualquiera pueda usar.
Duración del acceso explicada
Se admiten dos modelos:
| Escenario | access_duration_days | Comportamiento |
|---|---|---|
| Pase por tiempo | 30 | Cada espectador tiene 30 días desde el momento del canje |
| Pase de evento | null | Todos los espectadores tienen acceso hasta la fecha expires_at del código |
Listar códigos
/subscriber-codes/list.php?channel_id={id}
Recupera todos los códigos de suscriptor de tu canal, con estadísticas de canje.
Ejemplo
curl https://localtvbroadcast.com/api/mytvchannel/subscriber-codes/list.php?channel_id=42 \
-H "Authorization: Bearer TU_TOKEN"
Respuesta
{
"success": true,
"data": {
"codes": [
{
"id": 1,
"code": "A3F7K2N",
"url": "https://tu-canal.localtvbroadcast.com/?subscriber=A3F7K2N",
"label": "Pase mensual - Marzo",
"price": 9.99,
"currency": "USD",
"max_redemptions": 1,
"redemption_count": 0,
"expires_at": "2026-12-31T23:59:59+00:00",
"access_duration_days": 30,
"is_active": true,
"created_at": "2026-02-21 14:00:00"
}
]
}
}
Revocar un código
/subscriber-codes/revoke.php
Desactiva un código de suscriptor. El código ya no aceptará nuevos canjes. El acceso ya concedido sigue siendo válido hasta su propia fecha de caducidad.
Cuerpo de la solicitud
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
| code_id | integer | requerido | El ID del código a revocar (de la respuesta de generar o listar) |
Ejemplo
curl -X POST https://localtvbroadcast.com/api/mytvchannel/subscriber-codes/revoke.php \
-H "Authorization: Bearer TU_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "code_id": 1 }'
Canjear un código (App)
/subscriber-codes/redeem.php
Utilizado por la app My TV Channel cuando un espectador abre un enlace universal. Requiere autenticación de usuario. Idempotente — volver a canjear el mismo código devuelve el acceso existente.
Cuerpo de la solicitud
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
| code | string | requerido | El código de suscriptor de 7 caracteres |
Respuesta
{
"success": true,
"message": "Access granted",
"data": {
"channel": {
"id": 42,
"handle": "tu-canal",
"name": "Tu Canal",
"description": "...",
"thumbnail_url": "..."
},
"access_expires_at": "2026-04-21T14:00:00+00:00",
"already_redeemed": false
}
}
Nota: Este endpoint es llamado automáticamente por la app. No necesitas llamarlo desde tu servidor.
Validar un código (Reproductor web)
/subscriber-codes/validate.php
Utilizado por el reproductor web para validar un código de suscriptor antes de iniciar la reproducción. No requiere autenticación. Se llama automáticamente cuando un espectador abre un enlace de canal con ?subscriber=.
Cuerpo de la solicitud
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
| code | string | requerido | El código de suscriptor de 7 caracteres |
| channel_id | integer | requerido | ID del canal para validar |
Nota: Este endpoint es llamado automáticamente por el reproductor web. No necesitas llamarlo desde tu servidor.
Enlaces universales
Cada código se asigna a un enlace universal que funciona en todas partes:
https://{handle-de-tu-canal}.localtvbroadcast.com/?subscriber={CODIGO}
El enlace devuelto en la respuesta de generate está listo para compartir. Cuando un espectador hace clic:
| Escenario | Comportamiento |
|---|---|
| App instalada | Abre la app My TV Channel, concede acceso y muestra el canal |
| App no instalada | Abre el reproductor web en el navegador, valida el código e inicia la reproducción |
Los códigos no distinguen mayúsculas de minúsculas. A3F7K2N y a3f7k2n se tratan de forma idéntica. Los códigos solo usan los caracteres 2346789ACDEFGHJKMNPQRTUVWXYZ para evitar ambigüedad (sin 0/O, 1/I/L, 5/S, 8/B).
Integraciones
Integración con Stripe
Genera un código de suscriptor automáticamente cuando un pago de Stripe se completa. Añade este manejador de webhook a tu servidor:
// Express.js webhook handler for Stripe
const express = require('express');
const stripe = require('stripe')('sk_...');
const MY_TV_API = 'https://localtvbroadcast.com/api/mytvchannel';
const MY_TV_TOKEN = process.env.MY_TV_TOKEN; // Your JWT token
const CHANNEL_ID = 42; // Your channel ID
app.post('/webhooks/stripe', express.raw({ type: 'application/json' }), async (req, res) => {
const sig = req.headers['stripe-signature'];
const event = stripe.webhooks.constructEvent(req.body, sig, 'whsec_...');
if (event.type === 'checkout.session.completed') {
const session = event.data.object;
// Generate a subscriber code
const resp = await fetch(`${MY_TV_API}/subscriber-codes/generate.php`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${MY_TV_TOKEN}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
channel_id: CHANNEL_ID,
expires_at: '2027-01-01T00:00:00Z',
label: `Stripe ${session.id}`,
price: session.amount_total / 100,
currency: session.currency.toUpperCase(),
max_redemptions: 1,
access_duration_days: 30
})
});
const { data } = await resp.json();
// Send the link to your customer
await sendEmail(session.customer_email, {
subject: 'Your access link',
body: `Watch here: ${data.url}`
});
}
res.json({ received: true });
});
# Flask webhook handler for Stripe
import stripe, requests, os
from flask import Flask, request, jsonify
app = Flask(__name__)
stripe.api_key = 'sk_...'
MY_TV_API = 'https://localtvbroadcast.com/api/mytvchannel'
MY_TV_TOKEN = os.environ['MY_TV_TOKEN']
CHANNEL_ID = 42
@app.route('/webhooks/stripe', methods=['POST'])
def stripe_webhook():
sig = request.headers['Stripe-Signature']
event = stripe.Webhook.construct_event(request.data, sig, 'whsec_...')
if event['type'] == 'checkout.session.completed':
session = event['data']['object']
# Generate a subscriber code
resp = requests.post(
f'{MY_TV_API}/subscriber-codes/generate.php',
headers={
'Authorization': f'Bearer {MY_TV_TOKEN}',
'Content-Type': 'application/json'
},
json={
'channel_id': CHANNEL_ID,
'expires_at': '2027-01-01T00:00:00Z',
'label': f'Stripe {session["id"]}',
'price': session['amount_total'] / 100,
'currency': session['currency'].upper(),
'max_redemptions': 1,
'access_duration_days': 30
}
)
url = resp.json()['data']['url']
send_email(session['customer_email'], f'Watch here: {url}')
return jsonify(received=True)
// PHP webhook handler for Stripe
<?php
$payload = file_get_contents('php://input');
$sig = $_SERVER['HTTP_STRIPE_SIGNATURE'];
$event = \Stripe\Webhook::constructEvent($payload, $sig, 'whsec_...');
$myTvApi = 'https://localtvbroadcast.com/api/mytvchannel';
$myTvToken = getenv('MY_TV_TOKEN');
$channelId = 42;
if ($event->type === 'checkout.session.completed') {
$session = $event->data->object;
// Generate a subscriber code
$ch = curl_init("{$myTvApi}/subscriber-codes/generate.php");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer {$myTvToken}",
'Content-Type: application/json'
],
CURLOPT_POSTFIELDS => json_encode([
'channel_id' => $channelId,
'expires_at' => '2027-01-01T00:00:00Z',
'label' => "Stripe {$session->id}",
'price' => $session->amount_total / 100,
'currency' => strtoupper($session->currency),
'max_redemptions' => 1,
'access_duration_days' => 30
])
]);
$resp = json_decode(curl_exec($ch));
curl_close($ch);
// Send the link to your customer
mail($session->customer_email, 'Your access link', "Watch here: {$resp->data->url}");
}
http_response_code(200);
echo json_encode(['received' => true]);
Integración con Patreon (autoalojada)
Si prefieres ejecutar tu propio manejador de webhook en lugar de usar nuestra integración alojada, aquí te mostramos cómo manejar el evento members:pledge:create en tu servidor:
// Node.js - Patreon webhook handler
const crypto = require('crypto');
app.post('/webhooks/patreon', express.json(), async (req, res) => {
// Verify Patreon signature
const signature = req.headers['x-patreon-signature'];
const hash = crypto
.createHmac('md5', process.env.PATREON_WEBHOOK_SECRET)
.update(JSON.stringify(req.body))
.digest('hex');
if (signature !== hash) return res.status(403).send('Invalid signature');
const event = req.headers['x-patreon-event'];
const { data, included } = req.body;
if (event === 'members:pledge:create') {
const patron = included.find(i => i.type === 'user');
const email = patron?.attributes?.email;
const amountCents = data.attributes.currently_entitled_amount_cents;
// Only grant access for tiers >= $5
if (amountCents >= 500) {
const resp = await fetch(
'https://localtvbroadcast.com/api/mytvchannel/subscriber-codes/generate.php',
{
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.MY_TV_TOKEN}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
channel_id: 42,
expires_at: '2027-01-01T00:00:00Z',
label: `Patreon: ${email}`,
max_redemptions: 1,
access_duration_days: 30
})
}
);
const { data: codeData } = await resp.json();
// Send via Patreon message or your own email service
await sendEmail(email, {
subject: 'Your TV Channel access is ready!',
body: `Thanks for your support! Watch here: ${codeData.url}`
});
}
}
res.json({ received: true });
});
Webhook genérico / Pago personalizado
Para cualquier sistema de pago con webhooks (PayPal, Gumroad, LemonSqueezy, Ko-fi, Buy Me a Coffee, etc.), el patrón es el mismo:
Recibe el webhook de pago
Verifica la firma del webhook según la documentación de tu proveedor.
Llama al endpoint de generación
POST /subscriber-codes/generate.php con tu token JWT.
Entrega el enlace
Envía data.url a tu cliente por correo electrónico, redirección o mensaje en la app.
Ejemplo mínimo con cURL
# Generate a single-use code valid for 30 days of access
curl -X POST https://localtvbroadcast.com/api/mytvchannel/subscriber-codes/generate.php \
-H "Authorization: Bearer $MY_TV_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"channel_id": 42,
"expires_at": "2027-01-01T00:00:00Z",
"max_redemptions": 1,
"access_duration_days": 30
}'
# Response includes the link to share:
# "url": "https://your-channel.localtvbroadcast.com/?subscriber=A3F7K2N"
Manejo de errores
| Código HTTP | Significado |
|---|---|
| 200 | Exitoso |
| 400 | Campos faltantes o inválidos (consulta message para más detalles) |
| 401 | Token JWT inválido o caducado |
| 403 | El canal no pertenece al usuario autenticado |
| 404 | Código de suscriptor inválido o caducado (canjear/validar) |
| 500 | Error del servidor (reintentar) |