以您的方式
变现频道
连接Stripe、PayPal、Patreon或任何支付提供商。我们处理访问代码和邮件发送。您保留100%的收入。
无需编程
支持的支付提供商
选择您已在使用的支付提供商。我们负责连接、自动生成访问代码,并通过邮件向您的客户发送个人链接。
直接支付 — 我们为您托管结账页面
Stripe
接受银行卡、Apple Pay、Google Pay。我们使用您的API密钥创建Stripe Checkout会话。
托管结账Revolut Business
通过Revolut结账接受付款。快速设置,支持多种货币。
托管结账PayPal
接受PayPal付款。购买者可以使用PayPal账户或信用卡支付。
托管结账创作者平台 — 他们处理支付,我们处理访问
Patreon
赞助者在达到您的最低等级时自动获得访问权限。
Gumroad
将访问权限作为Gumroad产品出售。购买者在购买后获得链接。
LemonSqueezy
通过您的Lemon Squeezy商店出售访问权限。处理税务和付款。
Ko-fi
购买"咖啡"或加入会员的支持者将获得频道访问权限。
Buy Me a Coffee
支持者和会员自动获得您频道的访问权限。
您保留100%的收入。我们从不触碰您的资金。付款直接进入您在所选提供商的账户。我们只生成访问代码并通过邮件发送链接。
设置
连接您的提供商
登录,选择您的支付提供商,输入API凭证,我们将为您提供支付链接(Stripe/Revolut/PayPal)或webhook URL(Patreon/Gumroad等)。
在下方登录
使用您在My TV Channel应用中使用的同一Apple账户。
选择提供商并输入密钥
选择您的支付提供商并输入API密钥或webhook密钥。设置价格和时长。
分享您的链接
获取支付链接与您的受众分享,或将webhook URL粘贴到提供商的设置中。
连接您的支付提供商
使用您在应用中使用的同一Apple账户登录。
在哪里找到您的Stripe API密钥:前往Stripe控制台 → 开发者 → API密钥 → 复制您的密钥(以sk_live_开头)。
您的客户将收到什么
支付成功后,您的客户将收到一封包含个人访问链接的邮件:
您的访问已就绪
感谢您的购买!您现在可以访问您的频道名称。
立即观看此链接为个人专用,提供30天的访问权限。
概述
工作原理
您处理支付,我们处理访问。当客户向您付款时(通过您的网站、Stripe、Patreon或任何其他方式),您的服务器调用我们的API来生成唯一的访问代码。您将该代码作为链接提供给客户。
客户向您付款
在您的网站、Patreon或您选择的任何支付系统上。
您的服务器调用我们的API
生成具有您想要的过期时间和限制的订阅者代码。
客户获得链接
如:https://your-channel.localtvbroadcast.com/?subscriber=ABC2DEF
客户观看
在应用中打开(已授予访问权限)或直接在浏览器中播放。
您保留100%的收入。我们不处理支付也不收取佣金。订阅者代码只是在My TV Channel中授予您频道的访问权限。
入门
身份验证
所有发布者API调用都需要JWT令牌。通过您的My TV Channel账户登录获取:
# 登录获取JWT令牌
curl -X POST https://localtvbroadcast.com/api/mytvchannel/auth/login.php \
-H "Content-Type: application/json" \
-d '{
"email": "you@example.com",
"password": "your-password"
}'
响应中包含token字段。在所有后续请求中使用它:
Authorization: Bearer YOUR_JWT_TOKEN
请妥善保管您的令牌。将其存储为服务器端环境变量。切勿在客户端代码或公共代码库中暴露它。
基础URL
所有API端点使用以下基础URL:
https://localtvbroadcast.com/api/mytvchannel/subscriber-codes/
API参考
生成代码
/subscriber-codes/generate.php
为您的频道创建新的订阅者访问代码。需要身份验证和频道所有权。
请求体
| 字段 | 类型 | 必填 | 描述 |
|---|---|---|---|
| channel_id | integer | 必填 | 您的频道ID |
| expires_at | string | 必填 | 代码停止接受新兑换的ISO 8601日期 |
| label | string | 选填 | 内部标签(例如"VIP月度通行证") |
| price | number | 选填 | 您的价格(仅元数据,我们不处理支付) |
| currency | string | 选填 | ISO 4217货币代码(默认:USD) |
| max_redemptions | integer | 选填 | 最大使用次数。null = 无限制 |
| access_duration_days | integer | 选填 | 每次兑换的访问天数。null = 访问至expires_at |
示例
curl -X POST https://localtvbroadcast.com/api/mytvchannel/subscriber-codes/generate.php \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"channel_id": 42,
"expires_at": "2026-12-31T23:59:59Z",
"label": "Monthly Pass - March",
"price": 9.99,
"currency": "USD",
"max_redemptions": 1,
"access_duration_days": 30
}'
响应
{
"success": true,
"message": "Subscriber code generated",
"data": {
"id": 1,
"code": "A3F7K2N",
"url": "https://your-channel.localtvbroadcast.com/?subscriber=A3F7K2N",
"channel_id": 42,
"label": "Monthly Pass - March",
"price": 9.99,
"currency": "USD",
"max_redemptions": 1,
"expires_at": "2026-12-31T23:59:59+00:00",
"access_duration_days": 30
}
}
一次性代码 vs. 多次使用代码:设置max_redemptions: 1为每位客户生成唯一代码。设置为null则为任何人都可以使用的共享推广代码。
访问时长说明
支持两种模式:
| 场景 | access_duration_days | 行为 |
|---|---|---|
| 限时通行证 | 30 | 每位观众从兑换时起获得30天访问权 |
| 活动通行证 | null | 所有观众在代码的expires_at日期前都有访问权 |
代码列表
/subscriber-codes/list.php?channel_id={id}
获取您频道的所有订阅者代码及兑换统计。
示例
curl https://localtvbroadcast.com/api/mytvchannel/subscriber-codes/list.php?channel_id=42 \
-H "Authorization: Bearer YOUR_TOKEN"
响应
{
"success": true,
"data": {
"codes": [
{
"id": 1,
"code": "A3F7K2N",
"url": "https://your-channel.localtvbroadcast.com/?subscriber=A3F7K2N",
"label": "Monthly Pass - March",
"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"
}
]
}
}
撤销代码
/subscriber-codes/revoke.php
停用订阅者代码。该代码将不再接受新的兑换。已授予的访问权限在其自身到期前仍然有效。
请求体
| 字段 | 类型 | 必填 | 描述 |
|---|---|---|---|
| code_id | integer | 必填 | 要撤销的代码ID(来自生成或列表响应) |
示例
curl -X POST https://localtvbroadcast.com/api/mytvchannel/subscriber-codes/revoke.php \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "code_id": 1 }'
兑换代码(应用)
/subscriber-codes/redeem.php
当观众打开通用链接时由My TV Channel应用使用。需要用户认证。幂等 — 重新兑换同一代码将返回现有访问权限。
请求体
| 字段 | 类型 | 必填 | 描述 |
|---|---|---|---|
| code | string | 必填 | 7个字符的订阅者代码 |
响应
{
"success": true,
"message": "Access granted",
"data": {
"channel": {
"id": 42,
"handle": "your-channel",
"name": "Your Channel",
"description": "...",
"thumbnail_url": "..."
},
"access_expires_at": "2026-04-21T14:00:00+00:00",
"already_redeemed": false
}
}
注意:此端点由应用自动调用。您无需从服务器调用它。
验证代码(网页播放器)
/subscriber-codes/validate.php
网页播放器在开始播放前用于验证订阅者代码。无需认证。当观众打开带?subscriber=的频道链接时自动调用。
请求体
| 字段 | 类型 | 必填 | 描述 |
|---|---|---|---|
| code | string | 必填 | 7个字符的订阅者代码 |
| channel_id | integer | 必填 | 要验证的频道ID |
注意:此端点由网页播放器自动调用。您无需从服务器调用它。
通用链接
每个代码对应一个在任何地方都能使用的通用链接:
https://{your-channel-handle}.localtvbroadcast.com/?subscriber={CODE}
generate响应中返回的链接可以直接分享。当观众点击时:
| 场景 | 行为 |
|---|---|
| 已安装应用 | 打开My TV Channel应用,授予访问权限,显示频道 |
| 未安装应用 | 在浏览器中打开网页播放器,验证代码,开始播放 |
代码不区分大小写。A3F7K2N和a3f7k2n被视为相同。代码仅使用字符2346789ACDEFGHJKMNPQRTUVWXYZ以避免混淆(不含0/O、1/I/L、5/S、8/B)。
集成
Stripe集成
当Stripe支付成功时自动生成订阅者代码。将此webhook处理程序添加到您的服务器:
// 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]);
Patreon集成(自托管)
如果您更希望运行自己的webhook处理程序而不是使用我们的托管集成,以下是在您的服务器上处理members:pledge:create事件的方法:
// 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 / 自定义支付
对于任何带webhook的支付系统(PayPal、Gumroad、LemonSqueezy、Ko-fi、Buy Me a Coffee等),模式都是相同的:
接收支付webhook
根据提供商的文档验证webhook签名。
调用生成端点
使用JWT令牌调用POST /subscriber-codes/generate.php。
发送链接
通过邮件、重定向或应用内消息将data.url发送给客户。
最简cURL示例
# 生成一个有效期30天的一次性代码
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
}'
# 响应中包含要分享的链接:
# "url": "https://your-channel.localtvbroadcast.com/?subscriber=A3F7K2N"
错误处理
| HTTP状态码 | 含义 |
|---|---|
| 200 | 成功 |
| 400 | 缺少或无效的字段(查看message获取详情) |
| 401 | 无效或过期的JWT令牌 |
| 403 | 频道不属于已认证的用户 |
| 404 | 无效或过期的订阅者代码(兑换/验证) |
| 500 | 服务器错误(请重试) |