所有文章
Playbook阅读需 8 分钟

你的退款报告在 Apple、Google 和你的服务器之间从来对不上,教你如何逐笔核对

Apple 用两份报告展示退款,Google 又用两份,你的服务器还会看到第四种。这些数字没有一个能对上,而且这些差异是有意为之。这里解释为什么每个渠道对退款的归属方式各不相同,以及如何按笔交易将退款报告与你自己的记录核对。

一张会计师的办公桌上放着三叠分开的打印财务报告和一个放大镜,说明在 Apple 和 Google 之间核对退款报告有多难

要点

  • Apple 把退款报告拆分到两个工具里,它们在设计上就永远对不上。Sales and Trends 用 USD 快速估算退款,而 Payments and Financial Reports 稍后按 Apple 的财务日历结算退款。你服务器上的 REFUND 通知则是对同一事件的第三种实时视角。
  • 在 Apple 的 Summary Sales Report 里,一笔退款是独立的一行,Units 为负、Customer Price 为负,而且这份报告并没有把退款抵扣掉。如果你用肉眼去汇总某一列,就会数错,因为退款行是和销售行并排放在一起的,而不是相互抵销。
  • Apple 的财务报告采用 4-4-5 财务日历,而不是自然月,某个财务月的报告会在下一个财务月的第一个星期五之前发布。任何你拿来和普通自然月对比的退款合计,从一开始就会对不上。
  • Google Play 也用同样的方式区分退款。earnings report 把 Charge refund 和 Google fee refund 列为各自独立的交易类型,每一笔都标注 Full 或 Partial,而 estimated sales report 是低延迟的分析数据,Google 明确表示它不用于记账。
  • 退款按它结算的日期归属,而不是原始销售的日期,所以一笔 3 月购买的退款在两个商店里都会落到你 4 月的数字里。用 transaction id 来核对退款,绝不要靠对齐每月合计。
  • 开发者经常发现,在同一时间段内,REFUND 通知的数量比 Summary Sales Report 里的退款行还多,因为这两者统计的是不同的时刻。Apple 的 App Store Server API Get Refund History 端点才是核对的权威依据,每次核对一个 transaction id。
  • 这些渠道里只有两个是为记账而设计的:Apple 的 financial report 和 Google 的 earnings report。金额要拿这两个来核对,访问权限要拿你的服务器通知来核对,绝不要让一个数字去做另一个数字的工作。

从 App Store Connect 拉取退款数量,再从你的服务器拉取一次,这两个数字对不上。再从你的 financial report 拉取第三个,它和前两个也都对不上。这并不是谁的系统出了 bug。Apple 和 Google 各自都通过不止一个渠道报告退款,每个渠道统计的是退款生命周期中的不同时刻,而你的服务器看到的是第四种。如果你曾经试着核对退款报告,却因为各项合计越差越多而放弃,这里就讲清楚它们为什么会有差异、哪个数字该用在哪件事上,以及如何按交易而不是按月份把它们对齐。

为什么一笔退款会呈现为三个不同的数字

一笔退款在结算之前会经过好几个系统,而每个系统记录它的时刻都不一样。你的服务器最先听到它,作为一个事件。接着是一份快速分析报告对它进行估算。记账报告最后才记录它,也就是在钱真正划转之后。同一笔退款,三个时间戳,三个合计。错误在于把其中任意两个当成应该在同一天相等。

Apple 给你两大类报告,再加上你的 webhook

Apple 在两个地方报告退款,它们既不是同一个工具,也并不打算在某一天对得上。Sales and Trends 是快速的估算视图:每日报告在第二天发布,每周报告在星期一发布,每月报告在月末大约五天后发布,一般不迟于 Pacific 时间 8 a.m.。它用上个月汇率的滚动平均值以 USD 估算销售额和收入,这让它适合发现趋势,却不适合对账某一笔付款。Payments and Financial Reports 是结算后的视图:按 Apple 的财务日历每月生成一次,会在当前财务月的第一个星期五之前发布上一个财务月的报告,而且只有在该期间内存在购买或退款时才会生成。它使用应用于你付款的最终汇率。那份报告才是记账依据。除了这两者,你的服务器会在 Apple 批准退款的那一刻收到 App Store Server Notification REFUND,它以单个 transaction id 为键。

Google 也以同样的方式拆分

Google Play 是同样的拆分。earnings report 是记账依据,每月生成,通常在次月 5 日之前发布,它把退款列为各自独立的交易类型:Charge refund 表示退还给买家的金额,Google fee refund 表示 Google 退回的服务费,每一笔都标注 Full 或 Partial。estimated sales report 是低延迟的分析视图,显示买家在扣除税费之前支付的金额,Google 明确表示它适合用于分析,不建议用于记账。在服务器端,你会收到实时的 Real-time Developer Notification,还可以从 Voided Purchases API 读回一笔退款。

Apple 在报告里如何展示退款,以及负数行的陷阱

打开 Summary Sales Report,退款并不会悄悄地从某笔销售里扣掉自己。它会作为独立的一行出现。那一行的 Units 和 Customer Price 都是负数,这正是你发现退款的方式,而 Developer Proceeds 这个数值的表现方式和价格并不相同。这份报告本身并没有把退款抵扣掉。它把退款行放在销售行旁边,把它们归类是你自己的事。用肉眼去汇总 Units 列,你要么会重复计数,要么会完全漏掉退款,因为一个负一的退款行和你的正数销售处在同一列里。

实用规则很简单:通过负数 Units 找出退款,把这些行单独加起来,绝不要以为报告已经替你把它们抵扣掉了。你退款数量的一句话答案,是负 Unit 行的数量,而不是某一列的算术总和。

Apple 渠道用途更新时间退款如何呈现
Sales and Trends快速趋势估算,不用于记账每日在次日,每月在月末大约 5 天后趋势中的负数单位,以 USD 估算
Summary Sales ReportSales and Trends 背后可下载的明细与 Sales and Trends 相同的节奏独立的一行,Units 为负、Customer Price 为负
Payments and Financial Reports记账与付款记录按 Apple 的财务日历每月发布,不迟于第一个星期五从该财务月收入中结算扣除
REFUND 服务器通知实时访问控制Apple 批准退款的那一刻一个事件,一个 transaction id

财务日历就是你每月合计永远对不上的原因

这就是一份仔细的电子表格仍然无法对平的最大单一原因。Apple 的财务报告不按自然月运行。它们按 4-4-5 财务日历运行,其中大多数财务月是四周,每第三个月是五周。一个开发者拿 Financial Report 和一个普通的 1 月到 1 月的区间对比,其实是在对比两段不同的天数跨度,所以即使每个底层数字都正确,退款合计也不可能对上。正是出于这个原因,Apple 官方论坛上的开发者眼看着 Sales 数字和 Financial Report 数字相差数千美元,而且只要放任不管,差距每个月都在扩大。

Google 的 earnings report 是按月的,但它有自己的时间安排和自己的时区,两者都不是你服务器的 UTC 时钟。更深层的陷阱是两个商店共有的:退款按它结算的日期归属,而不是原始销售的日期。在 4 月初为一笔 3 月的购买退款,它会减少你 4 月的数字,而不是 3 月的。按标签把两个月对齐,退款看上去就像是从一个月里消失、又在另一个月里冒了出来。

两张打印的电子表格并排放着,一只手沿着同一行在两张表上比对,说明如何用 transaction id 核对退款报告

一笔退款的成本是多少,以及该在哪份报告里查看它

核对本质上是一个记账问题,所以要跟着钱走。发生退款时,商店会退回它自己的佣金,这意味着真正从你账户里流出的金额是你在这笔销售中的分成,而不是客户看到被退回的全款。在 Google Play 上,这笔退回是一条可见的行:你 earnings report 上的 Google fee refund 交易类型就是退回给你的服务费,它紧挨着退给买家的 Charge refund。在 App Store 上,Apple 扣除你扣佣后的收入,并在同一动作中退回它的佣金,所以 financial report 显示的扣除额已经扣掉了 Apple 的抽成。

现金流的时间点是开发者会感到意外的地方。在 Google Play 上,如果你在 Google 为某笔订单向你付款之前就退款,你根本不会收到那笔金额。如果你在付款之后退款,Google 会从未来的一次付款中扣除它。而如果一波退款把你的余额推成负数,并且持续为负至少 48 小时,Google 会从通常接收你付款的银行账户中扣除这笔差额。拒付是同一事件更尖锐的版本:在 Google Play 上,对于在 2026 年 8 月 3 日当天或之后下的订单,拒付会把购买价格加上银行手续费转嫁到开发者身上,而且它落在比销售更晚的一个月的报告里。

发生退款时App StoreGoogle Play
从你账户流出的你扣佣后的收入购买价格减去 Play 的服务费
商店退回的Apple 的佣金服务费,作为一条 Google fee refund 行
用哪份报告核对Payments and Financial ReportsEarnings report
何时结算处理它的那个财务月,不迟于其后的第一个星期五从该期间或下一期间的付款中扣除
拒付的转折Apple 吸收信用卡争议处理的一整套机制从 Aug 3 2026 起,价格加银行手续费转到你身上

如何一步步核对你的退款报告

一旦你不再试图让每个数字都相等,而是把每个数字分派给它所回答的问题,这件事就变简单了。问题只有两个:有多少钱发生了划转,以及谁还拥有访问权限。

  • 打开报告之前先确定问题。对于金额,答案就在 Apple 的 financial report 和 Google 的 earnings report 里,没有别的。对于访问权限,答案在你的服务器通知里。绝不要拿一个去核对另一个。
  • 选择 transaction id 作为贯穿这四个渠道的关联键。它是销售、它的退款、各份报告和你的 webhook 都共享的那一个字段。
  • 对于 Apple,当 Summary Sales Report 和你的 webhook 不一致时,调用 App Store Server API Get Refund History 端点 /inApps/v2/refund/lookup/{transactionId}。它返回某个客户已签名的退款交易,带有 revocationDate 和 revocationReason,每次针对一个 transaction id,并会分页遍历他们的历史记录。那个端点就是决胜项。
  • 对于 Google,把 earnings report 上的 Charge refund 行与 Voided Purchases API 针对同一批订单所报告的内容交叉核对,并记住部分退款会被标注为 Partial,不会把原始扣款清零。
  • 以报告的时钟为准,而不是你的。Apple 用的是 Pacific 时间下的财务月。Google 的 earnings report 有自己的月份和时区。你的日志几乎肯定是 UTC。在对比之前先转换到报告的日历,否则光是日期边界就会制造出虚假的不匹配。
  • 预期估算值会变动。Sales and Trends 是一个估算,会随着交易结算而不断变化。要拿 financial report 来核对,绝不要拿估算来核对,也绝不要拿昨天那份估算的快照来核对。

当你的服务器显示的退款比报告还多时

最常见的恐慌是发现在同一时间段内,你服务器上的 REFUND 通知比销售报告里的退款行还多。这通常并不是钱丢了。这两个渠道统计的是不同的时刻,一条通知可能比报告里的那一行早好几天,而且一笔部分退款或一次重新提交的请求都可能产生不止一个事件。开发者们报告过的正是这种情形:同一个月里数以千计的 REFUND 通知,对应着数量更少的负 Unit 行。每次都用同样的方式解决它:拿你服务器看到的那些 transaction id,把它们送进 Get Refund History,让 Apple 自己的记录来判定哪些真正退了款、退了多少。

简短版

你没办法让 Apple 的估算、Apple 的 financial report、Google 的 earnings report 和你的 webhook 在同一天全都显示相同的退款合计,你应该放弃这种尝试。每一个都按它被设计来告诉你的内容去读。金额上信任 financial report 和 earnings report,访问权限上信任你的服务器通知,当两个渠道打架时,用 transaction id 把它们关联起来,让 Get Refund History 或 Voided Purchases 查询来打破僵局。核对好的退款不是对上的合计。它们是对上的交易。

常见问题解答

为什么我的 App Store 销售和 financial report 对不上?
它们在不同的时钟上衡量不同的东西。Sales and Trends 是以 USD 计、采用滚动平均汇率的快速估算,而 Payments and Financial Reports 是按 Apple 的 4-4-5 财务日历、使用最终汇率的结算记账记录。因为财务月不是自然月,而且退款的结算比销售更晚,这两个合计在设计上就会有差异。凡是涉及金额的事,都用 financial report 来核对。
退款在 App Store Summary Sales Report 里是怎么显示的?
一笔退款会作为独立的一行出现,Units 为负、Customer Price 为负。这份报告并没有把退款抵扣掉,所以退款行是挨着销售行放的,而不是相互抵销。通过负数 Units 来识别退款,并把这些行单独汇总,因为用肉眼去汇总这一列会数错你的退款。
退款什么时候会出现在 Google Play 的 earnings report 里?
earnings report 每月生成,通常在次月 5 日之前发布。一笔退款会以两种交易类型出现:Charge refund 表示退还给买家的金额,Google fee refund 表示 Google 退回给你的服务费,每一笔都标注 Full 或 Partial。如果你在 Google 向你付款之前退款,你根本不会收到那笔金额;如果是在付款之后,它会从未来的一次付款中扣除。
为什么我的服务器显示的 REFUND 通知比我的销售报告还多?
因为这两者统计的是不同的时刻。你的服务器实时听到退款事件,而销售报告稍后才记录结算后的那一行,并且部分退款或重新提交的退款可能产生不止一条通知。要解决这个差异,拿你服务器看到的那些 transaction id,把它们送进 App Store Server API Get Refund History 端点,它会返回 Apple 自己关于实际退款情况的记录。
记账时我应该用哪个退款数字?
Apple 的 Payments and Financial Reports 和 Google Play 的 earnings report。那些是结算后的、达到记账级别的记录。Apple 的 Sales and Trends 和 Google 的 estimated sales report 是快速分析数据,两个商店都告诉你不要用于记账,而你的服务器通知是用于控制访问的,不是用于确认收入的。
退款会和原始销售出现在同一个月里吗?
通常不会。在两个商店里,退款都按它结算的日期归属,而不是原始购买的日期。一笔 3 月的销售在 4 月退款,会减少你 4 月的合计,所以按标签匹配两个月会让退款看上去像是从一个月里消失、又出现在另一个月里。改用 transaction id 来匹配。

来源和延伸阅读

RefundHalt

App Store 和 Google Play 退款自动驾驶

继续阅读

下一项退款请求已经在路上。

读完又一封关于未能申辩退款的支持邮件所需的时间,足够您完成 RefundHalt 设置。