あなたのチャンネルを
自由に収益化
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を設定。
アクセス期間の説明
2つのモデルがサポートされています:
| シナリオ | 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
}
}
注意:このエンドポイントはアプリによって自動的に呼び出されます。サーバーから呼び出す必要はありません。
コードを検証(Webプレーヤー)
/subscriber-codes/validate.php
再生開始前にWebプレーヤーがサブスクライバーコードを検証するために使用します。認証不要。視聴者が?subscriber=付きのチャンネルリンクを開いた時に自動的に呼び出されます。
リクエストボディ
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
| code | string | 必須 | 7文字のサブスクライバーコード |
| channel_id | integer | 必須 | 検証対象のチャンネルID |
注意:このエンドポイントはWebプレーヤーによって自動的に呼び出されます。サーバーから呼び出す必要はありません。
ユニバーサルリンク
各コードはどこでも機能するユニバーサルリンクに対応します:
https://{your-channel-handle}.localtvbroadcast.com/?subscriber={CODE}
generateレスポンスで返されるリンクはすぐに共有できます。視聴者がクリックすると:
| シナリオ | 動作 |
|---|---|
| アプリインストール済み | My TV Channelアプリが開き、アクセスが付与され、チャンネルが表示されます |
| アプリ未インストール | ブラウザでWebプレーヤーが開き、コードが検証され、再生が開始されます |
コードは大文字・小文字を区別しません。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署名を検証します。
生成エンドポイントを呼び出し
POST /subscriber-codes/generate.phpをJWTトークン付きで呼び出します。
リンクを配信
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 | サーバーエラー(再試行してください) |