XD-OP-08 · DOC

退款与对账

退款按业务单号幂等、按原订单冻结的收款分配快照发起回退;实际到账路径以支付服务方原交易与分账合同为准。本篇给出状态机、补偿与对账骨架。

小豆支付开放平台是面向已有自有系统的商家的支付接入服务:通过服务器对服务器的接口,把支付宝与微信收款接进商家自己的系统,并以签名事件通知回传支付状态;资金由持牌支付公司收付结算。个人也能申请:主体类型选「个人」,身份证 + 本人银行卡即可完成商户进件。央行持牌机构清算,安全可靠的个人和企业支付接口。

1. 退款接口

POST <BASE_URL>/api/open/v1/refunds
{
  "outTradeNo": "SHOP20260926A0001",
  "outRefundNo": "RF20260926A0001",
  "refundAmountFen": 100,
  "reason": "买家申请"
}
项规则
可退前提仅支付成功的订单可退
金额累计退款不得超过实付金额;失败的退款不占额度;超限返回 422 OPEN_API_LIMIT_EXCEEDED
幂等同 outRefundNo 同内容 → 200 幂等重放;同号异内容 → 409
受理后被拒502(支付机构拒绝,平台不向外暴露内部原因)
结果不确定状态 UNKNOWN,不判死,等事件收敛(见 §2)

退款状态:REQUESTED → PENDING → SUCCEEDED / FAILED(另有 UNKNOWN)。

一个容易踩的 409:退款按下单时冻结的收款分配快照发起回退(实际到账路径以支付服务方原交易与分账合同为准),因此前提是该单有可用的快照。缺少快照(历史单或异常单)时,创建退款返回 409 OPEN_API_STATE_INVALID——这表示该单不能自助退款,请带 outTradeNo 与 requestId 走官网反馈渠道人工处置,不要换号重试。

请只用查询退款接口和自己库里记录的 outRefundNo 判退款最终结果——不要用「发起退款后等待固定时长」这种猜测式判断。

2. 结果不确定(UNKNOWN)时的正确姿势

UNKNOWN 表示「平台与支付机构之间的结果暂时不可知」。正确处理是查证收敛,不是重做动作:

退款 UNKNOWN
 ├─ 等 REFUND_SUCCEEDED / REFUND_FAILED 事件(唯一自动收敛路径)
 ├─ 调 GET /api/open/v1/refunds/{outRefundNo} 看当前状态(本地权威读:不会触发外呼、也不会改变状态)
 └─ 长时间仍 UNKNOWN → 把该笔挂到「待核」队列,带 outRefundNo + requestId 走官网反馈人工介入
      ❌ 不要用新的 outRefundNo 再退一次(可能造成重复退款)
      ❌ 不要把 UNKNOWN 当失败直接回滚交付(可能钱已退)

别指望「反复查单」把状态查出来:查询接口是平台本地账本的只读投影,它不会去问支付机构——UNKNOWN 的收敛只发生在支付机构回通知时。人工兜底是最终手段。

订单侧同理:订单 UNKNOWN 时不要重新下单、不要判失败。

3. 对账

最小对账闭环(建议每日跑一次):

  1. 拉你自己的流水:以你的库为准(订单号、金额、状态)。
  2. 拉平台侧:逐笔 GET /api/open/v1/payments/{outTradeNo} 与 GET /api/open/v1/refunds/{outRefundNo}。
  3. 对齐三类差异:
差异处置
平台成功、你这边未成功你的事件消费漏了 → 按事件 eventId 补齐落账(这就是为什么要接事件 + 查单双路径)
你这边成功、平台未成功你的落账提前了 → 这是误判终态(多半把回跳/页面状态当成了终态),把交付动作回退到「以查单为准」
金额/费率不一致用该笔的 feeProjection(含 ruleVersion)核对,不要用你库里的费率表
  1. ruleVersion 对齐:若同一批订单的 ruleVersion 出现变化,说明期间发生过配置变更——按逐笔口径对,不要按批次统一算。但它只是全局配置版本:平台对单个商家调价不会改变它,所以逐笔核对要以该笔的 merchantRateBps / companyServiceFeeRateBps 为准,不能只看版本号有没有变。

4. 结算读回

  • 逐笔结算状态看门户「资金 / 结算」页(逐笔清单支持翻页);到账周期与口径以门户生效配置为准(见 费率与限额)。
  • 对账发现「平台已结算、你未入账」时:先看该笔订单的渠道与结算状态,再带着 outTradeNo + requestId 走官网反馈渠道。

5. 退款常见误区

  1. 用新的 outRefundNo 重试 UNKNOWN 的退款 → 重复退款。
  2. 把 502 直接当成「没退成功」 → 要先查退款状态再决定,502 只代表「本次请求被拒」。
  3. 按「发起时间 + 固定时长」判断到账 → 结算周期与渠道相关,会变。
  4. 对已关闭/已失败订单发退款 → 409/422,先查单确认订单状态。
内容源:open-platform/docs/08-refund-and-reconciliation.md · 最后更新 2026-10-17 下载本文 .md 在 GitHub 查看