11.3 税务表单与合规(W-8BEN 等)

平台第一次打款前会要你填一张税表:W-9、W-8BEN 还是 W-8BEN-E,取决于你是美国人还是外国人、是个人还是实体。本节只做工程落点——把表单选择、预扣千分比与信息申报表写成一张可机读表和一个可跑的 TypeScript 内核,并明确声明:表单填写与税务结论请咨询专业人士。

本节不提供任何税务意见。 下面讲的是「平台要你填哪张表、系统里怎么落这条规则」的工程问题;表单怎么填、你的具体税务结论是什么、能不能主张协定优惠,请咨询持牌税务专业人士。这一点先写在最前面。

站内那篇出海合规与税务风险清单 是一份风险清单:哪些地区有哪些坑、要办哪些手续、留哪些凭证。本节不重写那份清单,只把其中最容易被程序化的一段——平台侧的税表选择与预扣规则——做成一个可跑的工程落点。前两节(11.1 / 11.2)把「钱怎么来」算清楚了,这一节处理「钱在合规上要过哪一关」。

为什么会有 W-8BEN 这张表

海外平台(尤其是美国主体或经美国通道结算的平台)在给非美国收款方打款前,通常要求你声明税务身份。这个声明落在几张标准表单上:W-9 给美国纳税人用,W-8BEN 给非美国个人用,W-8BEN-E 给非美国实体用。表单不是走过场——它决定两件事:要不要预扣,以及用哪张信息申报表(给美国人的 1099,还是给非美国人的 1042-S)。填错表单(比如个人错填实体表),轻则被要求重填、打款延迟,重则被按最高默认税率预扣。

三张表单,一个选择逻辑

选择逻辑其实只有两个分叉。第一刀:你是美国人吗?是,走 W-9,通常不预扣,申报用 1099。不是,走第二刀。第二刀:你是个人还是实体?个人填 W-8BEN,实体填 W-8BEN-E。预扣率则取决于有没有主张税收协定优惠:主张了(且成立)用协定率,没主张用默认率。这条逻辑干净得可以直接写成代码——但**「协定优惠是否成立」是税务判定,不是代码能替你做主的**,代码只负责在给定前提下把结果算出来。

D 层:表单选择表

先把这张表写成纯数据。forms[].entity 是每张表单适用的主体类型;withholding 里放默认预扣率、协定预扣率与两张信息申报表的名字:

{
  "version": 1,
  "game": "merge-island",
  "observedAt": "2026-10",
  "note": "跨境结算的税务表单选择表。口径是「公开可观察机制」的建模假设(观察时点 2026-10,非实测),仅用于工程落点:forms[].entity=该表单适用的主体类型(individual/entity);withholding.defaultRatePermille=无税收协定时的默认预扣千分比(示例取 300=30%);withholding.treatyRatePermille=主张协定优惠后的示例预扣千分比;withholding.reportingForm=非美国人的信息申报表(1042-S);withholding.usForm=美国人的信息申报表(1099)。表单适用性、预扣率与协定优惠须以真实税务判定为准,命令行不可复现(X)。全整数,无浮点。本表不构成税务意见。",
  "forms": [
    { "id": "w9", "name": "W-9", "who": "美国纳税人(个人或实体)", "entity": ["individual", "entity"] },
    { "id": "w8ben", "name": "W-8BEN", "who": "非美国个人的受益所有人", "entity": ["individual"] },
    { "id": "w8ben-e", "name": "W-8BEN-E", "who": "非美国实体的受益所有人", "entity": ["entity"] }
  ],
  "withholding": {
    "payerCountry": "US",
    "defaultRatePermille": 300,
    "treatyRatePermille": 100,
    "reportingForm": "1042-S",
    "usForm": "1099"
  },
  "applicants": [
    { "id": "cn-indie", "entityType": "individual", "isUsPerson": false, "taxResidence": "CN", "hasTreaty": true },
    { "id": "de-studio", "entityType": "entity", "isUsPerson": false, "taxResidence": "DE", "hasTreaty": true },
    { "id": "us-llc", "entityType": "entity", "isUsPerson": true, "taxResidence": "US", "hasTreaty": false },
    { "id": "sg-dev", "entityType": "individual", "isUsPerson": false, "taxResidence": "SG", "hasTreaty": false },
    { "id": "fr-entity", "entityType": "entity", "isUsPerson": false, "taxResidence": "FR", "hasTreaty": true }
  ]
}

hasTreaty 只是建模开关,表示「该收款方是否主张了协定优惠」;它是否成立、能主张到什么税率,属于真实税务判定(X)。这些预扣率是示例值,不是任何真实税率。

P 层:表单选择与预扣内核

下面这段是 P 层 TypeScript 内核 core/src/g11/taxform.ts。它读同一份 config/g11_tax_form.json,把「主体类型 + 是否美国人 + 是否主张协定」映射成应填表单、预扣千分比与信息申报表。它只做规则映射,不构成任何税务意见:

// file: core/src/g11/taxform.ts
// tier: P
// verify: node --test 'core/test/g11_*.test.ts'
//
// 税务表单选择与预扣内核:读 config/g11_tax_form.json,按主体类型与税务居民身份
// 选出应填表单、给出预扣千分比与信息申报表。**本内核只做工程落点的规则映射,
// 不构成任何税务意见;表单填写与税务结论请咨询专业人士。**
// 全整数、地板除、无浮点、无随机、禁 Math.random;只用可擦除语法(禁 enum / namespace)。

export interface TaxForm {
  readonly id: string; readonly name: string; readonly who: string;
  readonly entity: readonly string[];
}
export interface WithholdingRule {
  readonly payerCountry: string; readonly defaultRatePermille: number;
  readonly treatyRatePermille: number; readonly reportingForm: string; readonly usForm: string;
}
export interface Applicant {
  readonly id: string; readonly entityType: string; readonly isUsPerson: boolean;
  readonly taxResidence: string; readonly hasTreaty: boolean;
}
export interface TaxConfig {
  readonly version: number; readonly game: string; readonly observedAt: string;
  readonly forms: readonly TaxForm[];
  readonly withholding: WithholdingRule;
  readonly applicants: readonly Applicant[];
}

export interface TaxDecision {
  readonly id: string; readonly form: string; readonly formName: string;
  readonly withholdingPermille: number; readonly reportingForm: string;
  readonly netPermille: number;
}

/** 表单选择:美国人 → W-9;非美国实体 → W-8BEN-E;非美国个人 → W-8BEN。 */
export function selectForm(a: Applicant): string {
  if (a.isUsPerson) return "w9";
  return a.entityType === "entity" ? "w8ben-e" : "w8ben";
}

/** 预扣千分比:美国人无预扣;非美国人主张协定优惠则用协定率,否则用默认率。 */
export function withholdingPermille(a: Applicant, w: WithholdingRule): number {
  if (a.isUsPerson) return 0;
  return a.hasTreaty ? w.treatyRatePermille : w.defaultRatePermille;
}

/** 信息申报表:美国人 1099,非美国人 1042-S。 */
export function reportingForm(a: Applicant, w: WithholdingRule): string {
  return a.isUsPerson ? w.usForm : w.reportingForm;
}

/** 预扣后净额:金额 − 金额 × 预扣千分比(地板除)。 */
export function netAfterWithholding(amountMinor: number, ratePermille: number): number {
  return amountMinor - Math.floor((amountMinor * ratePermille) / 1000);
}

function formName(cfg: TaxConfig, id: string): string {
  const f = cfg.forms.find((x) => x.id === id);
  return f === undefined ? id : f.name;
}

/** 对所有申请人批量决策。 */
export function decideAll(cfg: TaxConfig): TaxDecision[] {
  return cfg.applicants.map((a) => {
    const form = selectForm(a);
    const rate = withholdingPermille(a, cfg.withholding);
    return { id: a.id, form, formName: formName(cfg, form),
             withholdingPermille: rate, reportingForm: reportingForm(a, cfg.withholding),
             netPermille: 1000 - rate };
  });
}

/** 跨语言对拍摘要:主体:表单:预扣千分比:申报表。 */
export function digest(cfg: TaxConfig): string {
  return decideAll(cfg)
    .map((d) => `${d.id}:${d.form}:${d.withholdingPermille}:${d.reportingForm}`)
    .join(",");
}

配套测试 core/test/g11_taxform.test.ts 把一份独立手推的金标准摘要写死,断言内核逐字符相等,并逐项验证三分支表单选择、三档预扣率、两张申报表与整数净额:

// file: core/test/g11_taxform.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, selectForm, withholdingPermille, reportingForm,
  netAfterWithholding, type TaxConfig, type Applicant } from "../src/g11/taxform.ts";

const ROOT = join(dirname(fileURLToPath(import.meta.url)), "..", "..");
const cfg = JSON.parse(readFileSync(join(ROOT, "config", "g11_tax_form.json"), "utf8")) as TaxConfig;
const who = (id: string): Applicant => cfg.applicants.find((a) => a.id === id)!;

// 独立算出的金标准摘要(按规则表逐条手推,与实现无关)
const EXPECTED = "cn-indie:w8ben:100:1042-S,de-studio:w8ben-e:100:1042-S,"
  + "us-llc:w9:0:1099,sg-dev:w8ben:300:1042-S,fr-entity:w8ben-e:100:1042-S";

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

test("表单选择:个人/实体、美国/非美国三分支", () => {
  assert.equal(selectForm(who("cn-indie")), "w8ben");     // 非美国个人
  assert.equal(selectForm(who("de-studio")), "w8ben-e");  // 非美国实体
  assert.equal(selectForm(who("us-llc")), "w9");          // 美国实体
});

test("预扣千分比:美国人 0、协定 100、无协定 300", () => {
  const w = cfg.withholding;
  assert.equal(withholdingPermille(who("us-llc"), w), 0);
  assert.equal(withholdingPermille(who("cn-indie"), w), 100);
  assert.equal(withholdingPermille(who("sg-dev"), w), 300);
});

test("信息申报表:1099 与 1042-S 分界", () => {
  assert.equal(reportingForm(who("us-llc"), cfg.withholding), "1099");
  assert.equal(reportingForm(who("cn-indie"), cfg.withholding), "1042-S");
});

test("预扣后净额:整数地板除", () => {
  assert.equal(netAfterWithholding(100000, 100), 90000); // 预扣 10%
  assert.equal(netAfterWithholding(100000, 300), 70000); // 预扣 30%
  assert.equal(netAfterWithholding(100000, 0), 100000);  // 无预扣
});

test("批量决策:五个主体的净留存千分比", () => {
  const d = Object.fromEntries(decideAll(cfg).map((x) => [x.id, x.netPermille]));
  assert.equal(d["us-llc"], 1000);
  assert.equal(d["sg-dev"], 700);
  assert.equal(d["de-studio"], 900);
});

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

$ node --test core/test/g11_taxform.test.ts
✔ 跨语言一致:TS 表单决策摘要 == 独立金标准
✔ 表单选择:个人/实体、美国/非美国三分支
✔ 预扣千分比:美国人 0、协定 100、无协定 300
✔ 信息申报表:1099 与 1042-S 分界
✔ 预扣后净额:整数地板除
✔ 批量决策:五个主体的净留存千分比
ℹ tests 6
ℹ pass 6
ℹ fail 0

摘要本身也是税表规则回归测试的基准:

cn-indie:w8ben:100:1042-S,de-studio:w8ben-e:100:1042-S,us-llc:w9:0:1099,sg-dev:w8ben:300:1042-S,fr-entity:w8ben-e:100:1042-S

从摘要读出的三条工程结论

第一,表单选择是纯规则映射:五个主体里,cn-indie 与 sg-dev 两个非美国个人都选 W-8BEN,de-studio 与 fr-entity 两个非美国实体都选 W-8BEN-E,us-llc 选 W-9。这条逻辑可以完全自动化——把主体类型与税务身份作为配置项,表单类型由代码唯一确定。第二,预扣差异是量级差异:同样是中国人主体,主张协定(cn-indie,100‰)与未主张(sg-dev,300‰)在示例里差了 20 个百分点;一笔 100000 分的收入,预扣后分别是 90000 与 70000 分。第三,申报表跟着身份走:美国人拿 1099,非美国人拿 1042-S——收款方不会「选」申报表,它是身份的副产品。这三条合起来说明:税务表单的「选择」在系统里是确定性的,但「结论」不是——协定优惠成立与否、实际预扣率、要不要在居住地补税,全在代码边界之外。

这些属于 X 层:真实税务不可复现

下面这些属于 X 层,需真实业务环境,命令行不可复现:

  • 你的真实税务居民身份与受益所有人认定(不是你自己在配置里填个 true 就算);
  • 税收协定优惠是否成立、能主张到什么实际税率(示例里的 100‰ 只是占位);
  • 平台真实的预扣与申报行为(何时扣、扣多少、报给哪个税务机关);
  • 在居住地是否需要就这笔境外收入补税、如何申报。

工程上正确的做法是:把「规则映射」和「税务判定」分开——代码负责前者(选哪张表、按给定的率算净额、产出可回归的摘要),专业人士负责后者。系统里所有涉及税率的字段都应标注为「可配置的建模参数」,绝不硬编码成「真实税率」。

自检表

检查项合格标准
是否提供税务意见否,正文与内核均显式声明「请咨询专业人士」
表单选择可复算由主体类型 + 是否美国人唯一确定
预扣口径整数千分比,净额地板除,无浮点
申报表跟随身份1099 / 1042-S 由身份决定,非人为选择
参数可配置预扣率是建模参数,不硬编码为真实税率
边界清晰真实税务判定 / 协定成立 / 补税标 X

本节把「填税表」从「一件法律事务」拆出了一个可自动化的工程内核:表单选择、预扣计算、申报表映射,全都由规则唯一确定,且摘要可回归。而真正需要专业人士判断的部分,被显式划在代码边界之外。本章三节到此收尾:门槛(11.1)、汇率与费用(11.2)、税表(11.3)——跨境结算这条链上,能算的都用整数算清楚了,不能算的都标了 X。下一章进入出海风控,先看内容与版权的地区差异。

阅读导航:上一节:11.2 汇率、手续费与到账周期 · 下一节:12.1 内容与版权的地区差异 。

继续阅读

探索更多技术文章

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

全部文章 返回首页

「minigame」更多文章

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