未成年マーケットプレイスで Stripe Connect Express を運用する — Separate Charges & Transfers + 保護者名義出金 + 資金プール実装 (2026 年版)
Z 世代の稼ぐ手段として注目される『未成年マーケットプレイス』の商用実装は、決済と法規制の 2 面で難易度が跳ね上がります。Stripe Connect の 3 モデル (Standard / Express / Custom) から Express を選ぶ理由、Separate Charges & Transfers の分岐設計、未成年名義で Connect アカウントが作れない問題を保護者名義出金 + consent_token で解決する法務設計、資金プールと application_fee (15% Free / 12% Pro) の階層、返金と Reverse Transfer の TOCTOU 対策 (teen-earn B558 実バグ修正)、Account/Connect 2 系統 Webhook の二鍵署名 (B549)、通報 hold_period と takedown 後の grant 有効性 (B559)、特商法 + 資金決済法 + 未成年契約取消 + 児童売春禁止法 + 著作権の法務チェックリスト、FAQ 10 問を、sukikatsu (teen-earn) 本番実装知見でまとめます。
1. 未成年マーケットプレイスの需要 — Z 世代の稼ぐ手段と何が難しいか
2020 年代の Z 世代 (概ね 1997-2012 年生まれ) は SNS ネイティブで、 創作 / ハンドメイド / スキル販売を高校生のうちから始めるケースが 増えています。BOOTH のようなクリエイター向けマーケット、ココナラの ようなスキルマーケット、minne / Creema のようなハンドメイド EC が 既に成立しているものの、これらは 18 歳以上を前提とした利用規約で、未成年専用のマーケットプレイスは商用市場に空白が あります。
ClearNets の teen-earn プロジェクト (sukikatsu.clearnets.org) は、 この未成年ニッチに特化したマーケットプレイスを設計しています。 しかし実装で早々にぶつかる 2 つの壁があります。
- 決済の壁: Stripe / PayPay / LINE Pay 等の主要 決済事業者は KYC で 18 歳以上を要求。未成年名義で決済アカウントを 作ることが実質不可能。
- 法規制の壁: 民法 5 条 2 項の未成年契約取消権、 児童売春禁止法・児童福祉法の対面取引規制、特商法の販売業者表示 義務、資金決済法の前払式支払手段規制、著作権法上の二次創作対応、 の 5 領域を同時に満たす設計が必要。
本記事はこのうち 決済の壁 を Stripe Connect Express + 保護者名義出金 + 資金プール設計で解消する実装知見と、法規制の壁を 技術設計に落とし込む方法を、teen-earn 本番実装で得た知見でまとめます。
2. Stripe Connect の 3 モデル比較 — なぜ未成年案件で Express が最適か
Stripe Connect は 3 つの connected account タイプを提供しており、 個人開発者のマーケットプレイスにとって選定が最初の重要判断です。
| 項目 | Standard | Express | Custom |
|---|---|---|---|
| KYC 収集 | Stripe Dashboard (自社実装不要) | Onboarding UI 委譲 (自社実装不要) | 全て自社実装 (PCI DSS 対応) |
| Dashboard | Stripe 標準 Dashboard | 簡易版 Express Dashboard | 全て自社実装 |
| プラットフォーム制御 | 弱 (connected account 主導) | 中 (transfer/payout 制御可) | 強 (全操作制御可) |
| 開発工数 | 最小 (数時間) | 中 (数日) | 大 (数週間 + 監査) |
| PCI DSS | SAQ-A | SAQ-A | SAQ-D (自社対応必須) |
| 未成年適合性 | △ (制御不足) | ◎ (最適) | △ (オーバーヘッド) |
未成年マーケットプレイスで Express が最適な理由は 3 つ。
- KYC を Stripe に完全委譲: 18 歳未満の名義では KYC を通せないので、保護者名義で Express アカウントを作成する 設計が組みやすい。Custom で自社 KYC を組むと保護者判定ロジックを 全て自社実装する必要があり工数肥大。
- カード情報の非保持: 未成年案件は消費者庁 / 個人 情報保護委員会の関心対象になりやすく、機微情報を自社サーバに保持 しない設計 (PCI DSS SAQ-A) が説明しやすい。Custom は SAQ-D 要件 で年 1 回の外部監査が入る。
- 手数料の明示性: 保護者に「Stripe 手数料 3.6% + プラットフォーム take rate 15%」と Express Dashboard で明示できる。 Standard だと connected account が自身の Dashboard を持ち、 プラットフォーム側で手数料が見えにくい。
Merci (飲食店チップ SaaS) も同じ理由で Express を採用しており、 小規模事業者向けの Stripe Connect 実装では Express が国内標準的な 選択になっています。
3. Separate Charges & Transfers パターンの詳細
Stripe Connect の charge / transfer には 2 つの主要パターンがあります。
- Destination Charges: charge 作成時に destination パラメータで connected account を指定。charge 完了と同時に自動で 振替が走る「シンプル方式」。
- Separate Charges & Transfers: charge はプラット フォームが受け取り、後で明示的に transfer.create() で connected account に振替。「柔軟な資金プール方式」。
未成年マーケットプレイスでは Separate 一択です。 理由は、買主決済 → モデレーション審査 → hold_period 経過 → 通報 なし → transfer 実行という 3 段階の判定を挟む必要があるため。 Destination だと charge と同時に自動振替が走り、通報時の Reverse Transfer が返金全額按分で複雑化します。
Separate パターンの実装コード (Node.js 例):
// 1) 買主決済 (プラットフォームが charge を受ける)
const charge = await stripe.paymentIntents.create({
amount: 1000, // ¥1,000
currency: "jpy",
payment_method: pmId,
confirm: true,
metadata: {
listing_id: "listing_123",
buyer_user_id: "user_buyer_456",
seller_user_id: "user_seller_789",
parent_stripe_account: "acct_parent_abc", // 保護者名義 connected account
},
on_behalf_of: "acct_parent_abc", // 統計・払戻先の見せ方
}, {
idempotencyKey: `purchase-${orderId}`,
});
// 2) hold_period (7 日) 待機 & モデレーション審査 (別プロセス)
// 3) 通報なし & 審査通過 → 明示的に transfer 実行
const application_fee = calculateApplicationFee(1000); // ¥150 (15%)
const transfer = await stripe.transfers.create({
amount: 1000 - stripe_fee - application_fee, // 出品者手取り
currency: "jpy",
destination: "acct_parent_abc",
source_transaction: charge.latest_charge, // balance_transactions で紐付け
metadata: {
listing_id: "listing_123",
seller_user_id: "user_seller_789",
payout_lock_released_at: new Date().toISOString(),
},
}, {
idempotencyKey: `transfer-${orderId}`, // 二重 transfer 防止
});重要なパラメータ:
on_behalf_of: 決済上の見せ方を connected account 名義に する。買主のカード明細に『(サービス名) via ClearNets Marketplace』 のように表示される。統計上の税務処理にも影響。source_transaction: transfer が特定の charge に由来する ことを Stripe balance_transactions に記録。追跡性を担保。idempotencyKey: 二重 transfer を防ぐ冪等キー。orderId 単位で振ることで、リトライ時の重複実行を Stripe 側でブロック。
4. 未成年名義で Connect アカウントが作れない問題と保護者名義出金
Stripe Connect Onboarding は KYC 段階で 18 歳以上を要求します。 日本の場合、Individual アカウント作成時に運転免許・マイナンバー カード・パスポート等の生年月日情報を照合し、未成年名義では capability を有効化できません (transfers capability が pending から進まない)。
解決策は 保護者名義で Express アカウントを作成し、 未成年ユーザーの売上を保護者アカウントに transfer する 『保護者名義出金』設計です。データベース設計は以下。
-- users テーブル (未成年ユーザー)
CREATE TABLE users (
id BIGSERIAL PRIMARY KEY,
email VARCHAR(255) NOT NULL,
age INT NOT NULL,
is_minor BOOLEAN GENERATED ALWAYS AS (age < 18) STORED,
parent_stripe_account_id VARCHAR(64), -- 保護者の Stripe acct_xxx
parent_consent_token UUID, -- 保護者同意の hash
parent_consent_at TIMESTAMPTZ,
parent_consent_ip INET, -- 法務エビデンス
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- parent_consents テーブル (詳細エビデンス)
CREATE TABLE parent_consents (
id BIGSERIAL PRIMARY KEY,
minor_user_id BIGINT NOT NULL REFERENCES users(id),
parent_email VARCHAR(255) NOT NULL,
parent_name VARCHAR(128) NOT NULL,
parent_stripe_account_id VARCHAR(64) NOT NULL,
consent_token UUID NOT NULL DEFAULT gen_random_uuid(),
consent_scope JSONB NOT NULL, -- {marketplace: true, payout: true, ...}
consent_at TIMESTAMPTZ NOT NULL,
consent_ip INET NOT NULL,
consent_user_agent TEXT,
revoked_at TIMESTAMPTZ -- 保護者が同意撤回した場合
);保護者同意フロー (parent consent flow) の流れ:
- 未成年ユーザー登録時に「保護者メールアドレス」を入力させる。
- 保護者宛にマジックリンクを送信 (Resend / React Email)、 有効期限 72 時間 + 単発トークン。
- 保護者がリンクをクリック → 同意画面でStripe Connect Onboarding URL を生成、保護者に Express アカウント作成を促す。
- Onboarding 完了後、
account.updatedWebhook で transfers capability が active になったことを検知、parent_stripe_account_idを users テーブルに保存。 - 同時に
parent_consentsに consent_token + IP + UA を 記録し、法務エビデンスに残す。
重要な運用ポイント: 保護者メール不達への対応。 Gmail の迷惑メール振り分けや、キャリアメール (docomo / au / softbank) のフィルタで届かないケースが 5-10% 発生します。対策は (1) SPF / DKIM / DMARC の完全設定 (Resend + Cloudflare DNS)、(2) 送信元 ドメインを 3 ヶ月以上のウォームアップ済にする、(3) 不達時に SMS 経由 で consent_token を DB 直参照して手動 approve できる管理画面を用意、 の 3 段構え。teen-earn では (3) の Ops 画面で月 10-20 件の手動対応が 発生しています。
5. 資金プール設計 — Application Fee / min_payout / hold_period
マーケットプレイスの資金フローには 4 つの重要パラメータがあります。
- Application Fee (take rate): プラットフォームが 取る手数料率。teen-earn は Free プラン 15% / Pro プラン (¥500/月) 12% の階層設計。
- Stripe 手数料: 国内カード 3.6%、JCB / 一部 +¥40 相当。プラットフォームが吸収するか、出品者に転嫁するか設計判断。
- min_payout: 最小出金額。teen-earn は ¥1,000。 少額を溜め込むことで振込手数料の頻度を下げる。
- hold_period: 決済から transfer 実行までの待機 期間。teen-earn は 7 日 (通報期間としても機能)。
Application Fee 計算例 (¥1,000 の取引 / Free 15% / 国内カード):
取引額: ¥1,000 Stripe 手数料 (3.6%): -¥36 残額: ¥964 Application Fee: -¥144 (964 × 15%) 出品者手取り: ¥820 * 振込手数料 ¥250 は月 1 回の payout でまとめて負担 (小分けにしない) * min_payout ¥1,000 に達しない場合は次月へ繰越
Pro プラン (¥500/月 サブスク) では take rate が 12% に下がる設計 で、これにより ¥1,000 取引の Application Fee が ¥116 になり、 出品者手取りが ¥848 (+¥28)。月 20 件以上取引する出品者にとっては Pro プランが合理的になる価格設計です。
6. 返金 & 部分返金の Reverse Transfer 実装 (teen-earn B558 実バグ修正)
マーケットプレイス運営で最も事故りやすいのが返金処理です。 teen-earn の B558 バグは 3 件の二重出金が発生した実インシデントで、 修正過程で 3 つの重要な学びを得ました。
学び 1: Reverse Transfer フラグ必須
// ❌ 悪い例 (二重出金の原因)
await stripe.refunds.create({
payment_intent: piId,
amount: 1000,
});
// → プラットフォーム側で charge は返金されるが、
// connected account の残高は減らない = 二重出金
// ✅ 良い例 (Reverse Transfer)
await stripe.refunds.create({
payment_intent: piId,
amount: 1000,
reverse_transfer: true, // ← 必須
refund_application_fee: true, // ← application_fee も按分返金
}, {
idempotencyKey: `refund-${orderId}`,
});reverse_transfer: true を指定すると、Stripe が自動で connected account の残高から返金分を引き戻します。これを忘れると プラットフォームは全額返金するのに connected account は売上を 保持し続ける『二重出金』状態になり、事業として損失。
学び 2: TOCTOU 対策 (冪等キー)
charge の status を確認して refund を発行する間に、別のプロセス (ユーザーが返金ボタンを 2 回押した / Ops が同時操作した) が同じ charge に refund を発行するとレース条件で二重返金が起きます。 対策は idempotencyKey を orderId 単位で振ること。 Stripe API は同じ idempotencyKey で 24 時間以内に来た request は キャッシュされた response を返すため、二重実行が API 層でブロック されます。
学び 3: 部分返金の application_fee 按分
// ¥1,000 の取引 → ¥500 部分返金
// application_fee = ¥150 (charge 時)
// 按分後 application_fee 返金額 = ¥150 × (500/1000) = ¥75
await stripe.refunds.create({
payment_intent: piId,
amount: 500, // 部分返金額
reverse_transfer: true,
refund_application_fee: true, // ← Stripe が自動で ¥75 分の fee を返金
});
// 内部 ledger も同時更新 (transaction 内)
await db.transaction(async (tx) => {
await tx.insert(refunds).values({
order_id: orderId,
amount: 500,
fee_refunded: 75,
reason: 'partial_customer_request',
});
await tx.update(orders)
.set({ status: 'partial_refunded', refunded_amount: 500 })
.where(eq(orders.id, orderId));
});部分返金では refund_application_fee: true を明示すると Stripe が自動で按分計算 (¥150 × 0.5 = ¥75) してくれます。手動で 計算するとバグの温床になるので、Stripe の按分機能を信頼するのが 推奨。
7. Webhook 二鍵署名 — Account/Connect 2 系統 (teen-earn B549 の学び)
Stripe Connect プラットフォームでは Webhook が 2 系統存在します。
- Account Webhook: プラットフォーム自身の Stripe アカウントに関するイベント (charge / payout / dispute)。
- Connect Webhook: 接続された全 connected account の イベント (account.updated / capability.updated / payout.paid)。
それぞれ独立した signing secret を持ちます。teen-earn B549 は 1 つの endpoint (/api/stripe/webhook) で両系統を受けようとしたが、 片方の secret でしか署名検証していなかったバグで、Connect イベントの 50-70% が 401 で拒否される事態が発生。修正は endpoint を分離。
// ✅ 修正後: endpoint を 2 本に分離
// /api/stripe/webhook-account (Account Webhook 専用)
export async function POST(req: Request) {
const sig = req.headers.get("stripe-signature");
const body = await req.text();
const event = stripe.webhooks.constructEvent(
body, sig,
process.env.STRIPE_WEBHOOK_SECRET_ACCOUNT // ← Account 用 secret
);
// ...
}
// /api/stripe/webhook-connect (Connect Webhook 専用)
export async function POST(req: Request) {
const sig = req.headers.get("stripe-signature");
const body = await req.text();
const event = stripe.webhooks.constructEvent(
body, sig,
process.env.STRIPE_WEBHOOK_SECRET_CONNECT // ← Connect 用 secret
);
// ...
}Stripe Dashboard 側の設定も 2 系統を別々に登録:
- Account Webhook: Developers → Webhooks → Add endpoint → URL
/api/stripe/webhook-account、Listen to: 「Events on your account」を選択、対象イベントは payment_intent.* / charge.* / dispute.* / payout.* 等。 - Connect Webhook: 同じ画面で「Events on Connected accounts」を選択、URL
/api/stripe/webhook-connect、 対象イベントは account.updated / capability.updated / person.updated / payout.paid 等。
署名検証の失敗率をモニタリングするのが運用のコツ。Datadog / Sentry で 401 応答率が 1% を超えたらアラート、5% を超えたら緊急対応 (secret ローテ / endpoint 設定確認) の SOP を組みます。
8. Payout ロック / 通報保留 / takedown 後の grant 有効性 (B559 の学び)
マーケットプレイスの運営上、通報や違反判定時に売上を止める設計が 必要になります。teen-earn B559 で整理した 3 段の grant 有効性 チェック:
Step 1: 通報受理時の hidden 化 + payout_lock
// 通報 API
async function receiveReport(listingId, reason, reporterId) {
await db.transaction(async (tx) => {
// 出品を非表示化
await tx.update(listings)
.set({ status: 'hidden_pending_moderation', hidden_at: new Date() })
.where(eq(listings.id, listingId));
// pending transfer に payout_lock フラグ立て
await tx.update(pending_transfers)
.set({ payout_lock: true, payout_lock_reason: 'report_received' })
.where(and(
eq(pending_transfers.listing_id, listingId),
eq(pending_transfers.status, 'pending'),
));
// 通報レコード
await tx.insert(reports).values({
listing_id: listingId,
reason, reporter_id: reporterId,
status: 'pending_moderation',
});
});
}Step 2: モデレーション審査中の transfer ブロック
// transfer 実行前の事前チェック
async function executeTransfer(orderId) {
const pt = await db.query.pending_transfers.findFirst({
where: eq(pending_transfers.order_id, orderId),
});
// payout_lock 中は事前ブロック
if (pt.payout_lock) {
throw new Error(`Transfer blocked: ${pt.payout_lock_reason}`);
}
// hold_period (7 日) 未経過なら待機
if (Date.now() < pt.created_at.getTime() + 7 * 24 * 60 * 60 * 1000) {
throw new Error('Hold period not elapsed');
}
// 通過 → transfer.create() 実行
await stripe.transfers.create({ /* ... */ });
}Step 3: takedown 確定時の返金 + fee 全額返金
// takedown 確定 (モデレーターの判断)
async function takedownConfirmed(listingId) {
const orders = await db.query.orders.findMany({
where: and(
eq(orders.listing_id, listingId),
eq(orders.status, 'paid'),
),
});
for (const order of orders) {
// 全額返金 + Reverse Transfer + fee 全額返金
await stripe.refunds.create({
payment_intent: order.stripe_payment_intent,
reverse_transfer: true,
refund_application_fee: true, // fee も全額返金
reason: 'requested_by_customer',
metadata: { takedown_case_id: listingId },
}, {
idempotencyKey: `takedown-refund-${order.id}`,
});
}
// 出品者 KYC 記録に事案 log
await db.insert(seller_violations).values({
seller_id: listing.seller_id,
violation_type: 'takedown_confirmed',
listing_id: listingId,
log: 'Full refund + fee returned',
});
}逆に takedown 見送り確定時は payout_lock を解除して transfer 実行。 Payout の hold_period (7 日) を通報期間としても機能させることで、 越境返金 (transfer 実行後の返金で Reverse Transfer が connected account の残高不足で失敗するケース) が発生しない設計になります。
9. 法務チェックリスト — 5 領域の弁護士確認事項
未成年マーケットプレイスの日本法務チェックポイントを 5 領域で 整理します。
| 領域 | 法律 | 技術対応 |
|---|---|---|
| 特商法 | 特定商取引に関する法律 | 各出品ページに販売業者名 (or 保護者名) + 住所 + 連絡先。プラットフォーム自体も特商法表記必須。 |
| 資金決済法 | 資金決済に関する法律 | プラットフォーム内 wallet を実装しない (Stripe 即時 transfer 方式)。前払式支払手段該当を回避。 |
| 未成年契約取消 | 民法 5 条 2 項 | 保護者同意 (consent_token) を DB 記録。同意撤回 API + 30 日以内取消受付フロー。 |
| 児童売春禁止法 | 児童福祉法 34 条 / 児童売春禁止法 | 未成年プロフィール: 連絡先非公開 / 対面取引禁止 / 実名不要 / DM 機能制限 / 通報 SLA 24h。 |
| 著作権法 | 著作権法 (二次創作) | DMCA / 侵害申告窓口 + takedown SOP 24h。二次創作ガイドライン明示。 |
相場感: 初回法務レビュー 30-50 万円 (規約 + プライバシーポリシー + 特商法表記 + 保護者同意設計)、その後の月次相談 3-10 万円。金融 法制と青少年保護法制の両方に強い弁護士は少なく、事前に法律事務所 3-5 社に電話ヒアリングして選定するのが推奨。
10. FAQ
本記事の要点を 10 問の FAQ にまとめました。JSON-LD の FAQPage 構造化データも埋め込んでいるため、Google 検索でリッチリザルト 表示の対象になります。
Q1. 未成年ユーザーは Stripe Connect アカウントを作れますか?
Stripe の Connect Onboarding は 18 歳以上を前提としており、日本の 場合も KYC (本人確認) 段階で運転免許・マイナンバーカード等の年齢 確認が入るため、未成年名義で Express / Custom アカウントを作成 することは実質不可能です。teen-earn (sukikatsu) では保護者名義で Stripe Express アカウントを作成し、未成年ユーザーの売上を保護者 アカウントに transfer する『保護者名義出金』設計を採用しています。 事前に規約で『18 歳未満は保護者同意 + 保護者名義口座への出金』を 明示し、consent_token を DB 保存して法務エビデンスに残します。
Q2. Standard / Express / Custom のうちどれを選ぶべきですか?
未成年マーケットプレイスなら Express が最適です。理由は (1) KYC 収集を Stripe 側の Onboarding UI に完全委譲でき自社実装不要、 (2) カード情報保持義務 (PCI DSS SAQ-D) を回避でき自社で機微情報を 扱わない、(3) 手数料が明示的で保護者への説明が容易、の 3 点。 Standard は connected account が自身の Dashboard を持ちプラット フォームの制御が弱い、Custom は KYC・ダッシュボード全て自社実装で 個人開発者にはオーバーヘッド過大。Merci (飲食店チップ SaaS) も 同じ理由で Express を採用しています。
Q3. Separate Charges & Transfers と Destination Charges の使い分けは?
未成年マーケットプレイスは Separate Charges & Transfers 一択です。 Destination Charges は charge 時に destination パラメータで自動的に connected account に振替が走り、返金時の Reverse Transfer が同時 実行される『シンプルだが柔軟性が低い』方式。Separate は (1) プラット フォームがまず charge を受け、(2) 判定 (通報保留 / 資金プール保留 / hold period) を通過した後に、(3) 明示的に transfer を実行する 3 段階。 未成年案件では『買主決済後にモデレーション審査を挟む』『通報中は payout を止める』要件があり、Separate でないと柔軟な資金プール管理が できません。
Q4. Application Fee (take rate) はどう設計するのが標準ですか?
国内マーケットプレイス相場は 10-20% で、teen-earn (sukikatsu) は Free プラン 15%、Pro プラン 12% の階層設計を採用しています。Stripe の決済手数料 (国内カード 3.6%) + 振込手数料 (¥250/回) はプラット フォーム側が負担する『表示価格 = 出品者手取り』方式が UX 上優位。 Application Fee の計算式は (取引額 - Stripe 手数料 - 振込手数料) × take_rate、min_payout (¥1,000) と hold_period (7 日) をあわせて設計 します。数式で application_fee_amount を毎回計算し、charge 作成時に amount と同時に指定します。
Q5. Reverse Transfer で返金する時の注意点は?
3 つの落とし穴があります。(1) refund.create() 実行時に reverse_transfer: true を明示しないと、プラットフォーム側で charge は返金されるが connected account の残高は減らず『二重出金』状態に なる。(2) TOCTOU (Time of Check to Time of Use) — charge の status を 確認して refund 発行するまでの間に、別のプロセスが同 charge に対して refund を発行するとレース条件で二重返金が起きるため冪等キー (idempotency_key) 必須。(3) 部分返金では refund_application_fee: true を指定し application_fee 分も按分返金する。teen-earn の B558 バグ 修正は (1) が原因で 3 件の二重出金が発生し、Reverse Transfer フラグの 追加 + 冪等キー付与 + 部分返金の按分ロジック整備で解消しました。
Q6. Webhook の二鍵署名検証とは何ですか?
Stripe Connect プラットフォームでは Account Webhook と Connect Webhook の 2 系統があり、それぞれ独立した signing secret を持ちます。 Account Webhook は自プラットフォームの Stripe アカウントに関する イベント (charge / payout / dispute) を通知、Connect Webhook は接続 された connected account の全イベント (account.updated / capability.updated / payout.paid) を通知。teen-earn B549 のバグは 1 つの endpoint で両系統を受けていたが片方の secret でしか署名検証 していなかったケースで、Connect イベントが 401 で拒否される事態が 発生。修正は endpoint を 2 本に分離し、Stripe Dashboard の Webhook 設定でも Account 用と Connect 用を別途登録、それぞれ STRIPE_WEBHOOK_SECRET_ACCOUNT / STRIPE_WEBHOOK_SECRET_CONNECT 環境変数で検証。
Q7. 通報や takedown 後の transfer / payout の扱いはどうしますか?
teen-earn B559 で整理した設計は 3 段の grant 有効性チェックです。 (1) 通報受理時に該当出品を hidden 化し、既存の pending transfer に payout_lock フラグ立て、(2) モデレーション審査中は当該 connected account の transfer.create() 呼び出しを事前ブロック、(3) takedown 確定時は返金 (Reverse Transfer) + application_fee 全額返金 + 出品者 KYC 記録に事案 log。逆に takedown 見送り確定時は payout_lock を解除 して transfer 実行。Payout の hold_period (7 日) を通報期間として 活用することで、越境返金が発生しない設計になります。
Q8. Apple / Google の IAP 手数料 30% と Stripe Connect 3.6% + take rate の使い分けは?
Apple / Google のガイドライン上『物理的商品・実体サービスの決済』は Stripe 等の外部決済が許容、『デジタルコンテンツ・アプリ内消費物』は 原則 IAP 必須というルール分岐です。teen-earn (sukikatsu) は『イラスト 受注 / ハンドメイド / 手作りグッズ』が中心のためスキン/コスメ/物理 商品扱いで Stripe Connect が使えます。逆に Kotodama (AI 占い) や kotsukotsu (習慣トラッカー Pro) はサブスク型デジタルサービスで IAP 必須。Merci (飲食店チップ) は『実店舗での接客対価』で Stripe 使用可。 ガイドライン解釈は年に 1-2 回改正されるため、リリース前に App Store Review Guidelines 3.1.1 / 3.1.3 を最新版で確認するのが必須です。
Q9. 少額決済 (¥100-500) の最適設計は?
Stripe の国内カード決済手数料は 3.6% + ¥40 相当 (JCB / 一部) で、 少額決済ほど手数料負担率が高くなります。¥100 の決済に対して手数料 ¥43 で take rate 15% を乗せると、出品者手取りが ¥42 になり事業として 成立しません。対策は (1) 最低取引額を ¥500 or ¥1,000 に設定、(2) 複数商品のカート決済で 1 charge にまとめる、(3) プリペイド残高 (Stripe Customer Balance) で少額を溜め込み、¥3,000 以上でまとめて transfer、の 3 手法。teen-earn は (1) を採用し最低取引額 ¥500 の運用で 開始、成長に応じて (2) (3) を追加する段階設計です。
Q10. 日本の法務チェックポイントは何を確認すべきですか?
5 つを弁護士確認します。(1) 特定商取引法 — マーケットプレイス表示 事項 (販売業者名・住所・連絡先) を各出品ページで表示、プラット フォーム自体も特商法表記必須。(2) 資金決済法 — Stripe 経由の即時 transfer は前払式支払手段に該当しないが、プラットフォーム内 wallet を 実装するとアウト。(3) 未成年契約取消 — 民法 5 条 2 項『法定代理人の 同意なき法律行為は取消可能』のため、事前に保護者同意 + consent_token DB 保存が必須。(4) 児童売春禁止法 — 未成年出品者のプロフィール要件 (連絡先非公開 / 対面取引禁止 / 実名不要) を規約強制。(5) 著作権法 — 二次創作・トレース疑義への対応窓口 + takedown SOP。相場は初回法務 レビュー 30-50 万円、その後の運用相談で月 3-10 万円です。
11. まとめ — Express + Separate + 保護者名義出金が国内標準解
本記事の要点を 5 つに集約します。
- 未成年マーケットプレイスでは Stripe Connect Express + 保護者名義出金 + Separate Charges & Transfersが国内標準解。KYC を Stripe 委譲、機微情報非保持、柔軟な資金プール 管理が同時に実現可能。
- 保護者同意フロー は consent_token + IP + UA を DB 保存し法務 エビデンス化。メール不達 5-10% への Ops 手動 approve フロー必須。
- Reverse Transfer + 冪等キー + application_fee 按分返金 の 3 点を返金処理で明示。 teen-earn B558 の二重出金バグは全て Reverse Transfer フラグ漏れが原因。
- Account/Connect の Webhook 二鍵署名 を分離実装。1 endpoint 2 secret は運用崩壊。 teen-earn B549 で 50-70% イベント喪失事故。
- 5 領域の法務チェック (特商法 / 資金決済法 / 未成年契約取消 / 児童売春禁止法 / 著作権) を 初回 30-50 万円、月次 3-10 万円の弁護士予算で運用継続。
ClearNets の teen-earn (sukikatsu.clearnets.org) は本記事の設計を 全て実装した未成年専用マーケットプレイスとして稼働開始しています。 並行して、Free ユーザー向けにはより軽量な習慣化 / セルフ管理アプリ として kotsukotsu.clearnets.org も提供中で、Z 世代のセルフ管理と マネタイズの両輪を目指しています。Stripe Connect の実装に迷って いる個人開発者・スタートアップの参考にしてください。
ClearNets のマネタイズ支援プロダクト
sukikatsu (teen-earn) と kotsukotsu
本記事の実装設計を全て組み込んだ未成年専用マーケットプレイス sukikatsu (Stripe Connect Express + 保護者名義出金 + Separate Charges & Transfers) と、Z 世代向けセルフ管理 PWA kotsukotsu (¥400/月 Stripe Payment Link) が稼働中です。
この記事を書いた背景
teen-earn (sukikatsu) 本番実装で得た Stripe Connect Express の 実運用知見と、B558 / B549 / B559 の実バグ修正の学びを一次情報 として整理しました。本記事は法的アドバイスではなく事業設計の 参考情報です。実際の事業立ち上げ前には必ず金融法制・青少年保護法制 両方に強い弁護士のレビューを受けてください。特商法・資金決済法・ 民法・児童福祉法・著作権法は改正が続く分野で、最新情報は消費者庁 (caa.go.jp) / 金融庁 (fsa.go.jp) / こども家庭庁 (cfa.go.jp) の 公式発表を参照ください。