以您的方式
变现频道

连接Stripe、PayPal、Patreon或任何支付提供商。我们处理访问代码和邮件发送。您保留100%的收入。

支持的支付提供商

选择您已在使用的支付提供商。我们负责连接、自动生成访问代码,并通过邮件向您的客户发送个人链接。

直接支付 — 我们为您托管结账页面

Stripe

接受银行卡、Apple Pay、Google Pay。我们使用您的API密钥创建Stripe Checkout会话。

托管结账

Revolut Business

通过Revolut结账接受付款。快速设置,支持多种货币。

托管结账

PayPal

接受PayPal付款。购买者可以使用PayPal账户或信用卡支付。

托管结账

创作者平台 — 他们处理支付,我们处理访问

Patreon

赞助者在达到您的最低等级时自动获得访问权限。

Webhook

Gumroad

将访问权限作为Gumroad产品出售。购买者在购买后获得链接。

Webhook

LemonSqueezy

通过您的Lemon Squeezy商店出售访问权限。处理税务和付款。

Webhook

Ko-fi

购买"咖啡"或加入会员的支持者将获得频道访问权限。

Webhook

Buy Me a Coffee

支持者和会员自动获得您频道的访问权限。

Webhook

您保留100%的收入。我们从不触碰您的资金。付款直接进入您在所选提供商的账户。我们只生成访问代码并通过邮件发送链接。

连接您的提供商

登录,选择您的支付提供商,输入API凭证,我们将为您提供支付链接(Stripe/Revolut/PayPal)或webhook URL(Patreon/Gumroad等)。

1

在下方登录

使用您在My TV Channel应用中使用的同一Apple账户。

2

选择提供商并输入密钥

选择您的支付提供商并输入API密钥或webhook密钥。设置价格和时长。

3

分享您的链接

获取支付链接与您的受众分享,或将webhook URL粘贴到提供商的设置中。

连接您的支付提供商

使用您在应用中使用的同一Apple账户登录。

通过Apple登录

在哪里找到您的Stripe API密钥:前往Stripe控制台 → 开发者 → API密钥 → 复制您的密钥(以sk_live_开头)。

您的客户将收到什么

支付成功后,您的客户将收到一封包含个人访问链接的邮件:

您的访问已就绪

感谢您的购买!您现在可以访问您的频道名称

立即观看

此链接为个人专用,提供30天的访问权限。

开发者指南

工作原理

您处理支付,我们处理访问。当客户向您付款时(通过您的网站、Stripe、Patreon或任何其他方式),您的服务器调用我们的API来生成唯一的访问代码。您将该代码作为链接提供给客户。

1

客户向您付款

在您的网站、Patreon或您选择的任何支付系统上。

2

您的服务器调用我们的API

生成具有您想要的过期时间和限制的订阅者代码。

3

客户获得链接

如:https://your-channel.localtvbroadcast.com/?subscriber=ABC2DEF

4

客户观看

在应用中打开(已授予访问权限)或直接在浏览器中播放。

您保留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/

生成代码

POST /subscriber-codes/generate.php

为您的频道创建新的订阅者访问代码。需要身份验证和频道所有权。

请求体

字段类型必填描述
channel_idinteger必填您的频道ID
expires_atstring必填代码停止接受新兑换的ISO 8601日期
labelstring选填内部标签(例如"VIP月度通行证")
pricenumber选填您的价格(仅元数据,我们不处理支付)
currencystring选填ISO 4217货币代码(默认:USD
max_redemptionsinteger选填最大使用次数。null = 无限制
access_duration_daysinteger选填每次兑换的访问天数。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日期前都有访问权

代码列表

GET /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"
      }
    ]
  }
}

撤销代码

POST /subscriber-codes/revoke.php

停用订阅者代码。该代码将不再接受新的兑换。已授予的访问权限在其自身到期前仍然有效。

请求体

字段类型必填描述
code_idinteger必填要撤销的代码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 }'

兑换代码(应用)

POST /subscriber-codes/redeem.php

当观众打开通用链接时由My TV Channel应用使用。需要用户认证。幂等 — 重新兑换同一代码将返回现有访问权限。

请求体

字段类型必填描述
codestring必填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
  }
}

注意:此端点由应用自动调用。您无需从服务器调用它。

验证代码(网页播放器)

POST /subscriber-codes/validate.php

网页播放器在开始播放前用于验证订阅者代码。无需认证。当观众打开带?subscriber=的频道链接时自动调用。

请求体

字段类型必填描述
codestring必填7个字符的订阅者代码
channel_idinteger必填要验证的频道ID

注意:此端点由网页播放器自动调用。您无需从服务器调用它。

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等),模式都是相同的:

1

接收支付webhook

根据提供商的文档验证webhook签名。

2

调用生成端点

使用JWT令牌调用POST /subscriber-codes/generate.php

3

发送链接

通过邮件、重定向或应用内消息将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服务器错误(请重试)