11.1 平台收款方式与门槛

海外平台的收款方式五花八门:电汇、PayPal、Payoneer、平台内余额、支票,门槛从 10 美元到 200 美元不等,周期 7 到 45 天。本节把收款方式与门槛整理成一张可机读登记表,用 P 层 TypeScript 内核以全整数(最小单位 + 千分比 + 整数天数、地板除)复算门槛触发、结转与净到账。

站内那篇独立游戏全球财务与多币种架构 讲的是资金架构:多币种账户怎么开、税务身份怎么摆、主体怎么搭。本节不重写那套架构,只做一件更具体的事——平台侧到底有哪几种把钱打给你的方式,各自的门槛、周期与手续费是什么。那篇讲「结构」,本节讲「平台后台里那个提现按钮背后的规则」。

本章三节是一条链:本节(11.1)先看清收款方式与门槛,11.2 把汇率、手续费与到账周期做成可跑的整数模型,11.3 处理税务表单(W-8BEN 等)的工程落点。三节都只做工程与算术,不给任何税务或法律意见。

平台不会直接把钱打到你卡上

小游戏平台把广告收入结算给你时,钱不会「自动进银行卡」。它先在你平台账户里累积成一个可提现余额,然后你主动(或平台按周期自动)发起一次打款,钱才经过某个收款通道到达你手里。这个通道有几个硬参数:门槛(余额低于门槛不给打)、周期(多久结算一次)、手续费(比例 + 固定)、支持主体(个人 / 企业)。任何一个没对齐,你都会卡在「钱在平台上,但提不出来」或者「提出来了,但被手续费吃掉一大块」。

收款方式的四个维度

维度变化量踩坑示例
门槛触发打款的最低余额平台内余额 10 美元即可,支票要 200 美元
周期从发起到到账的天数Payoneer 7 天,电汇 30 天,支票 45 天
手续费比例费 + 固定费PayPal 按比例,电汇按笔固定 25 美元
主体个人 / 企业多数电汇只对企业主体开放

门槛最容易被忽略:它不是一个「越快越好」的参数。门槛低,你能经常拿到钱,但每笔都要吃一次固定手续费;门槛高,单笔成本摊薄,但现金流被压住——钱躺在平台账户里,既不能花也不能周转。所以「选哪种收款方式」本质上是在手续费和现金流之间做取舍。

D 层:收款方式与门槛登记表

先把这张表写成纯数据。thresholdMinor 是触发打款的最低余额(结算币种最小单位,美元即分),feePermille 是按金额收取的手续费千分比,fixedFeeMinor 是每笔固定手续费,payoutCycleDays 是整数天数,entity 是该方式支持的主体类型:

{
  "version": 1,
  "game": "merge-island",
  "observedAt": "2026-10",
  "note": "海外小游戏平台的收款方式与门槛登记表。口径是「公开可观察机制」的建模假设(观察时点 2026-10,非实测):thresholdMinor=触发打款的最低余额(结算币种最小单位,美元即分);payoutCycleDays=结算周期天数(整数);feePermille=按金额收取的手续费千分比;fixedFeeMinor=每笔固定手续费(最小单位);entity=该方式支持的主体类型(individual/entity);regionNote=公开可见的地区或主体限制说明。monthlyAccruedMinor=某平台月度累计可提现金额(建模假设)。真实门槛、真实手续费、真实结算周期与真实到账需真实业务环境,命令行不可复现(X)。全整数,无浮点。",
  "methods": [
    { "id": "platform_balance", "name": "平台内余额", "currency": "USD", "thresholdMinor": 1000, "payoutCycleDays": 30, "feePermille": 0, "fixedFeeMinor": 0, "entity": ["individual", "entity"], "regionNote": "余额留存在平台账户内,需绑定提现通道后才出金" },
    { "id": "payoneer", "name": "Payoneer", "currency": "USD", "thresholdMinor": 5000, "payoutCycleDays": 7, "feePermille": 15, "fixedFeeMinor": 0, "entity": ["individual", "entity"], "regionNote": "个人与企业均可,到账最快" },
    { "id": "paypal", "name": "PayPal", "currency": "USD", "thresholdMinor": 5000, "payoutCycleDays": 14, "feePermille": 20, "fixedFeeMinor": 0, "entity": ["individual", "entity"], "regionNote": "部分高风控地区需额外验证" },
    { "id": "bank_wire", "name": "银行电汇", "currency": "USD", "thresholdMinor": 10000, "payoutCycleDays": 30, "feePermille": 0, "fixedFeeMinor": 2500, "entity": ["entity"], "regionNote": "多数平台仅对企业主体开放,固定费高" },
    { "id": "check", "name": "支票邮寄", "currency": "USD", "thresholdMinor": 20000, "payoutCycleDays": 45, "feePermille": 0, "fixedFeeMinor": 500, "entity": ["entity"], "regionNote": "门槛最高、周期最长,仅少数平台保留" }
  ],
  "platforms": [
    { "id": "poki", "name": "Poki", "method": "bank_wire", "monthlyAccruedMinor": 7800 },
    { "id": "crazygames", "name": "CrazyGames", "method": "paypal", "monthlyAccruedMinor": 12300 },
    { "id": "gamedistribution", "name": "GameDistribution", "method": "payoneer", "monthlyAccruedMinor": 4500 },
    { "id": "armorgames", "name": "Armor Games", "method": "platform_balance", "monthlyAccruedMinor": 900 },
    { "id": "y8", "name": "Y8", "method": "check", "monthlyAccruedMinor": 21000 },
    { "id": "newgrounds", "name": "Newgrounds", "method": "paypal", "monthlyAccruedMinor": 3200 },
    { "id": "kongregate", "name": "Kongregate", "method": "bank_wire", "monthlyAccruedMinor": 15600 }
  ]
}

注意这些数字是「公开可观察机制」口径的建模假设(观察时点 2026-10),不是任何平台后台的实测:真实门槛、真实手续费与真实到账属于 X 层。

P 层:门槛决策内核

真正要落地的是决策逻辑:给定一个平台的累计余额和一种收款方式,判断够不够门槛、触发后净到账多少、差多少才够。下面这段是 P 层 TypeScript 内核 core/src/g11/payout.ts,它读同一份 config/g11_payout_methods.json,把手续费、门槛触发、结转与到账周期折成可复算的整数决策:

// file: core/src/g11/payout.ts
// tier: P
// verify: node --test 'core/test/g11_*.test.ts'
//
// 平台收款方式与门槛内核:读 config/g11_payout_methods.json,把「余额是否够门槛、
// 触发后净到账多少、差多少才够门槛」折成可复算的整数决策。
// 全整数、地板除、无浮点、无随机、禁 Math.random;只用可擦除语法(禁 enum / namespace)。

export interface PayoutMethod {
  readonly id: string; readonly name: string; readonly currency: string;
  readonly thresholdMinor: number; readonly payoutCycleDays: number;
  readonly feePermille: number; readonly fixedFeeMinor: number;
  readonly entity: readonly string[]; readonly regionNote: string;
}
export interface PlatformAccrual {
  readonly id: string; readonly name: string; readonly method: string;
  readonly monthlyAccruedMinor: number;
}
export interface PayoutConfig {
  readonly version: number; readonly game: string; readonly observedAt: string;
  readonly methods: readonly PayoutMethod[];
  readonly platforms: readonly PlatformAccrual[];
}

/** 一次打款的决策结果。deferredMinor 是本次未能提走、结转到下一周期的余额。 */
export interface PayoutDecision {
  readonly platform: string; readonly method: string; readonly currency: string;
  readonly accruedMinor: number; readonly thresholdMinor: number;
  readonly triggered: boolean; readonly feeMinor: number; readonly netMinor: number;
  readonly deferredMinor: number; readonly cycleDays: number;
}

/** 手续费 = 金额 × 千分比(地板除)+ 固定费。全整数,无浮点。 */
export function feeOf(amountMinor: number, m: PayoutMethod): number {
  return Math.floor((amountMinor * m.feePermille) / 1000) + m.fixedFeeMinor;
}

/** 净到账 = 金额 − 手续费。 */
export function netOf(amountMinor: number, m: PayoutMethod): number {
  return amountMinor - feeOf(amountMinor, m);
}

/** 还差几个周期才够门槛:整数上取整 (threshold + per − 1) // per;per ≤ 0 时返回 0。 */
export function cyclesToThreshold(perCycleMinor: number, thresholdMinor: number): number {
  if (perCycleMinor <= 0) return 0;
  if (thresholdMinor <= 0) return 0;
  return Math.floor((thresholdMinor + perCycleMinor - 1) / perCycleMinor);
}

/** 单平台的打款决策:够门槛才出金,不够则整笔结转。 */
export function gate(accruedMinor: number, m: PayoutMethod): {
  triggered: boolean; feeMinor: number; netMinor: number; deferredMinor: number;
} {
  const triggered = accruedMinor >= m.thresholdMinor;
  if (!triggered) {
    return { triggered: false, feeMinor: 0, netMinor: 0, deferredMinor: accruedMinor };
  }
  const feeMinor = feeOf(accruedMinor, m);
  return { triggered: true, feeMinor, netMinor: accruedMinor - feeMinor, deferredMinor: 0 };
}

function methodOf(cfg: PayoutConfig, id: string): PayoutMethod {
  const m = cfg.methods.find((x) => x.id === id);
  if (m === undefined) throw new Error(`未知收款方式:${id}`);
  return m;
}

/** 对所有平台批量决策。 */
export function decideAll(cfg: PayoutConfig): PayoutDecision[] {
  return cfg.platforms.map((p) => {
    const m = methodOf(cfg, p.method);
    const g = gate(p.monthlyAccruedMinor, m);
    return {
      platform: p.id, method: m.id, currency: m.currency,
      accruedMinor: p.monthlyAccruedMinor, thresholdMinor: m.thresholdMinor,
      triggered: g.triggered, feeMinor: g.feeMinor, netMinor: g.netMinor,
      deferredMinor: g.deferredMinor, cycleDays: m.payoutCycleDays,
    };
  });
}

/** 跨语言对拍摘要:平台:方式:是否触发:手续费:净到账,逐字符可比对。 */
export function digest(cfg: PayoutConfig): string {
  return decideAll(cfg)
    .map((d) => `${d.platform}:${d.method}:${d.triggered ? 1 : 0}:${d.feeMinor}:${d.netMinor}`)
    .join(",");
}

/** 本期实际出金总额(仅统计触发的平台)。 */
export function totalPaidOut(decisions: readonly PayoutDecision[]): number {
  return decisions.filter((d) => d.triggered).reduce((s, d) => s + d.netMinor, 0);
}

配套测试 core/test/g11_payout.test.ts 把一份独立手算的金标准摘要写死,断言内核逐字符相等,并逐项验证手续费、门槛触发、结转与周期:

// file: core/test/g11_payout.test.ts
// tier: P
// verify: node --test 'core/test/g11_*.test.ts'
//
// 硬断言:收款门槛内核的整数决策与「独立算出的金标准摘要」逐字符一致,
// 并逐项验证手续费(千分比 + 固定费)、门槛触发、结转与到账周期。

import { test } from "node:test";
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import { fileURLToPath } from "node:url";
import { dirname, join } from "node:path";

import { digest, decideAll, gate, feeOf, netOf, cyclesToThreshold, totalPaidOut,
  type PayoutConfig, type PayoutMethod } from "../src/g11/payout.ts";

const ROOT = join(dirname(fileURLToPath(import.meta.url)), "..", "..");
const cfg = JSON.parse(readFileSync(join(ROOT, "config", "g11_payout_methods.json"), "utf8")) as PayoutConfig;
const method = (id: string): PayoutMethod => cfg.methods.find((m) => m.id === id)!;

// 独立算出的金标准摘要(与内核实现无关,按整数公式逐笔手算)
const EXPECTED = "poki:bank_wire:0:0:0,crazygames:paypal:1:246:12054,"
  + "gamedistribution:payoneer:0:0:0,armorgames:platform_balance:0:0:0,"
  + "y8:check:1:500:20500,newgrounds:paypal:0:0:0,kongregate:bank_wire:1:2500:13100";

test("跨语言一致:TS 门槛决策摘要 == 独立金标准", () => {
  assert.equal(digest(cfg), EXPECTED);
});

test("手续费:千分比地板除 + 固定费(电汇固定 $25)", () => {
  const wire = method("bank_wire");
  assert.equal(feeOf(15600, wire), 2500); // 0% + 固定 2500
  const paypal = method("paypal");
  assert.equal(feeOf(12300, paypal), 246); // 12300*20//1000 = 246
  assert.equal(netOf(12300, paypal), 12054);
});

test("门槛触发:低于门槛整笔结转,达到门槛才出金", () => {
  const wire = method("bank_wire");
  assert.deepEqual(gate(7800, wire), { triggered: false, feeMinor: 0, netMinor: 0, deferredMinor: 7800 });
  const paypal = method("paypal");
  assert.deepEqual(gate(12300, paypal), { triggered: true, feeMinor: 246, netMinor: 12054, deferredMinor: 0 });
});

test("还差几个周期够门槛:整数上取整", () => {
  assert.equal(cyclesToThreshold(4500, 5000), 2);   // 差一点,仍要等下个周期
  assert.equal(cyclesToThreshold(7800, 10000), 2);
  assert.equal(cyclesToThreshold(900, 1000), 2);
  assert.equal(cyclesToThreshold(0, 1000), 0);      // 无进账
  assert.equal(cyclesToThreshold(1000, 1000), 1);   // 正好够
});

test("批量决策:本期出金总额只算触发的平台", () => {
  const decisions = decideAll(cfg);
  assert.equal(decisions.length, 7);
  const triggered = decisions.filter((d) => d.triggered).map((d) => d.platform);
  assert.deepEqual(triggered, ["crazygames", "y8", "kongregate"]);
  assert.equal(totalPaidOut(decisions), 45654); // 12054 + 20500 + 13100
});

test("到账周期:三种方式给出整数天数", () => {
  const d = Object.fromEntries(decideAll(cfg).map((x) => [x.platform, x.cycleDays]));
  assert.equal(d["crazygames"], 14); // PayPal
  assert.equal(d["kongregate"], 30); // 电汇
  assert.equal(d["y8"], 45);         // 支票
});

在本机跑 node --test 'core/test/g11_payout.test.ts',6 个用例全过:

$ node --test core/test/g11_payout.test.ts
✔ 跨语言一致:TS 门槛决策摘要 == 独立金标准
✔ 手续费:千分比地板除 + 固定费(电汇固定 $25)
✔ 门槛触发:低于门槛整笔结转,达到门槛才出金
✔ 还差几个周期够门槛:整数上取整
✔ 批量决策:本期出金总额只算触发的平台
✔ 到账周期:三种方式给出整数天数
ℹ tests 6
ℹ pass 6
ℹ fail 0

摘要本身也是门槛回归测试的基准:

poki:bank_wire:0:0:0,crazygames:paypal:1:246:12054,gamedistribution:payoneer:0:0:0,armorgames:platform_balance:0:0:0,y8:check:1:500:20500,newgrounds:paypal:0:0:0,kongregate:bank_wire:1:2500:13100

门槛的三个现实含义

看这七行决策就够读出三个结论。第一,门槛会把小额收入整笔结转:poki 月度累计 7800 分(78 美元)低于电汇门槛 10000 分(100 美元),整笔 7800 分结转到下个周期——不是消失,而是「看得见提不出」。gamedistribution(4500 分 < Payoneer 门槛 5000 分)、armorgames(900 分 < 平台内余额门槛 1000 分)、newgrounds(3200 分 < PayPal 门槛 5000 分)同样被卡住。第二,固定费与比例费的取舍取决于单笔大小:电汇固定 25 美元,对 15600 分(156 美元)的 kongregate 来说吃掉 16%,对更大金额则摊薄;PayPal 的 2% 对小额更友好。第三,本期真正出金的只有三个平台,净出金总额 45654 分(456.54 美元)——另外四个平台的收入在账上结转,不构成这个月的现金流。

这三条对现金流规划是致命的:如果你的收入高度依赖「门槛高的电汇」,而各平台月度余额又长期低于门槛,你会陷入账面有收入、卡里没现金的状态。工程上的正确做法是把门槛与周期一起纳入现金流模型——这正是下一节要做的整数建模。

这些数字不能靠命令行复现(X)

收款方式登记表是**「公开可观察机制」的建模假设**,不是权威数据源:真实门槛、真实手续费、真实结算周期、真实主体限制与真实到账表现都需要真实业务环境,命令行无法复现,标为 X。真正能复现的,是给定这张表之后的门槛触发、手续费与结转计算——那部分本节的 TS 内核用全整数(最小单位 + 千分比 + 整数天数、地板除一次)算到底,摘要与独立手算逐字符一致。

自检表

检查项合格标准
是否用浮点承载金额否,全程最小单位整数;手续费千分比 + 固定费
门槛口径清晰门槛标「公开可观察机制」+ 观察时点,不写「实测」
结转可见低于门槛的余额显式记为 deferredMinor,不丢失
周期整数到账周期为整数天数,无小数
摘要可复算digest 由整数公式唯一确定,与独立手算一致
边界清晰真实门槛 / 手续费 / 到账标 X,不写成「实测」

本节把「提现」从「点一下按钮」变成了一张可复算的门槛表:余额够不够、手续费吃掉多少、钱什么时候到。但到账金额里还藏着一个更大的变量——汇率,以及手续费到底按哪个币种扣。下一节把汇率、手续费与到账周期做成一条可跑的整数模型,并对照不同收款方式与不同目标币种。

阅读导航:上一节:10.3 隐私沙盒与聚合上报 · 下一节:11.2 汇率、手续费与到账周期 。

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「minigame」更多文章

  1. 附录 F:全书公式、参数与数据集索引
  2. 9.3 同意管理与数据出境
  3. 9.2 COPPA 与儿童向游戏的限制