站内那篇独立游戏全球财务与多币种架构 讲的是资金架构:多币种账户怎么开、税务身份怎么摆、主体怎么搭。本节不重写那套架构,只做一件更具体的事——平台侧到底有哪几种把钱打给你的方式,各自的门槛、周期与手续费是什么。那篇讲「结构」,本节讲「平台后台里那个提现按钮背后的规则」。
本章三节是一条链:本节(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 汇率、手续费与到账周期 。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。