SMARTPAY

QRPH 跨行清算失败怎么排查?从回执码定位问题的分层诊断方法(2026)

我在马尼拉负责一家连锁餐饮品牌的支付系统,门店和线上点单都挂着 QRPH 码。去年有段时间运营同事几乎每天都来问同一个问题:"顾客说付了,后台没看到,是不是清算失败了?"一开始我们只能靠人工翻后台、问网关客服,后来才意识到,大多数"清算失败"其实不是一个问题,而是一组被混在一起的问题,只有把回执码拆开看,才知道该找谁、改什么。关于商户视角的到账排查清单,我们在QRPH 收款没到账排查清单里写过;这篇文章专讲技术层面:一笔 QRPH 跨行支付在哪些环节会失败,每个环节的回执码长什么样,怎么从码反推责任方,以及怎么把这套诊断逻辑做进系统里,而不是每次靠人去猜。

先把一笔 QRPH 跨行支付拆成几层

QRPH 是菲律宾央行主导的全国统一二维码标准,它本身不是一条清算通道,而是一套"码的规范"。当付款人用 A 钱包或 A 银行的 App 扫你的 QRPH 码,而你的收款账户开在 B 机构,这笔交易就是跨行的,资金要经过实时清算网络才能从 A 侧到 B 侧。链路大致是:付款人 App → 付款方机构(发起方)→ 实时清算网络 → 收款方机构(接收方)→ 支付网关或收单系统 → 商户回调与后台。关于清算与结算的区别,实时支付清算是什么一文已经展开,这里只强调一点:每一层都可能失败,而且每一层的失败会以不同的方式"告诉"你。付款人侧的失败通常直接显示在他的 App 上;清算层的失败以状态原因码的形式返回给发起方和接收方;接收方和网关层的失败则体现在网关的订单状态和回调里;而商户系统自己的失败,往往是回调没处理好,交易其实已经成功。

这就是为什么"清算失败"这个词会误导排查。付款人 App 提示失败、钱没扣,是发起方或清算层拒绝;付款人显示成功、商户后台没记录,大概率是接收方之后的环节出了问题,资金已经在路上甚至已经到账。两类问题的处理路径完全不同,排查的第一步永远是:先确认这笔钱到底停在了哪一层。

回执码有几套,分别从哪里来

排查时你会遇到至少三套码,它们分别来自不同的层,不能混用。第一套是清算层的状态原因码。菲律宾的实时清算网络采用 ISO 20022 报文体系,交易被拒或超时时会返回标准化的原因码,这类码通常由字母加数字组成,对应"账户问题""金额问题""时限问题""系统问题"等类别。第二套是接收方机构或支付网关自己定义的业务状态码,比如订单不存在、金额不匹配、商户状态异常、重复通知等,这些码的命名由各家文档决定。第三套是传输层的错误,包括 HTTP 状态码、签名校验失败、超时、连接被拒等,它们和支付本身无关,但会导致你拿不到前两套码。

下面这张表是我们内部整理的对照,把常见的原因码类别、它大致代表什么、责任方在哪一层、以及商户技术团队能做什么放在一起。需要说明的是,具体码值和含义以你所接机构的技术文档为准,表里的示例取自 ISO 20022 体系中通用的状态原因码类别,不代表任何一家机构的完整清单。

码的类别常见示例(ISO 20022 体系)通常意味着责任方所在层商户侧动作
账户类AC01 账号格式错误、AC04 账户已关闭、AC06 账户被冻结收款账户信息有误或状态异常接收方机构 / 商户配置核对网关里登记的收款账户,联系收单机构确认账户状态
金额类AM02 超出允许金额、AM04 余额不足、AM05 重复交易付款人余额不足,或触发单笔、累计限额发起方机构 / 付款人引导付款人换方式或拆单;检查你是否生成了重复订单
权限与风控类AG01 交易被禁止、AG03 交易类型不支持、RR04 监管原因付款方或收款方风控规则拦截,或商户类别受限发起方或接收方风控确认商户类别码与经营范围一致;联系收单机构了解是否触发风控
时限类TM01 超过截止时间、AB03 清算超时中止清算网络或某一方未在规定时间内响应清算层 / 任意一方系统不要重复发起;先查询订单终态,必要时等待自动冲正
系统类AB05 接收方处理超时、AB06 清算系统超时、AB07 接收方离线某一方系统维护或故障接收方 / 清算层对照维护公告;切换备用通道;事后对账
网关业务码ORDER_NOT_FOUND、AMOUNT_MISMATCH、MERCHANT_SUSPENDED 等网关层校验不通过网关 / 商户系统按网关文档逐项修正,这类问题几乎都在商户自己或网关配置上
传输层错误HTTP 401/403、签名不匹配、连接超时你和网关之间的通信有问题商户系统 / 网络检查密钥、时间戳偏差、IP 白名单、重试策略

四类失败怎么对应到四种处理策略

把码分完类之后,处理策略其实只有四种。第一种是付款方问题,包括余额不足、付款人限额、付款方风控,这类失败商户做什么都没用,正确动作是把清晰的提示给到付款人,并给出备选方式,比如换另一家钱包的 App 再扫同一张 QRPH 码。第二种是收款方配置问题,账户关闭、账户冻结、商户类别受限都属于这一类,这类失败会持续发生在每一笔交易上,是最需要紧急处理的,因为它不是个案而是全量故障。第三种是时限与系统问题,这类失败最容易被误判,因为付款人那边可能已经扣款,清算层正在等待终态或者冲正,商户此时最忌讳的是让付款人"再付一次",正确做法是查询终态并等待。第四种是商户自身问题,包括回调地址不可达、验签失败、订单重复、金额校验写错,这类问题的特征是交易在网关侧已经成功,只是你的系统没有正确记账。

我们内部的经验是:先看码属于哪一类,再决定是"通知付款人""改配置""等待终态"还是"修自己的代码"。把这四条路径固化成规则之后,一线运营不需要理解 ISO 20022 也能做出正确的第一反应。

排查流程:从商户后台到清算回执的五步

遇到一笔疑似失败的交易,我们现在固定走五步。第一步,在自己的订单系统里找到这笔订单,确认它的本地状态和创建时间。第二步,用网关的订单查询接口查这笔订单在网关侧的状态,重点看 channel_status 和 clearing_reason_code 两个字段(字段名以你的网关文档为准),这一步往往就能定位问题所在的层。第三步,如果网关侧显示成功而本地显示未支付,检查回调日志,看是没收到、收到了验签失败、还是收到了处理报错。第四步,如果网关侧显示失败并带有清算层原因码,按上表归类,决定是通知付款人还是改配置。第五步,如果网关侧状态是处理中且超过了正常窗口,不要人工干预,等待终态或冲正,把这笔订单放进待复核队列,次日对账时统一处理。下面是查询接口的一个简化示例:

curl -X GET "https://api.example-gateway.ph/v1/orders/{{OUT_TRADE_NO}}" \
  -H "X-Merchant-Id: {{MERCHANT_ID}}" \
  -H "X-Timestamp: {{UNIX_TS}}" \
  -H "X-Sign: {{SIGNATURE}}"

# 典型返回(节选,字段名以网关文档为准)
# {
#   "out_trade_no": "POS-20261013-000871",
#   "channel": "QRPH",
#   "channel_status": "FAILED",
#   "clearing_reason_code": "AM04",
#   "clearing_reason_desc": "Insufficient funds",
#   "payer_institution": "BANK_A",
#   "payee_institution": "BANK_B",
#   "updated_at": "2026-10-13T11:42:07+08:00"
# }

第二段是我们把分类逻辑做进系统的骨架。核心思想是维护一张"码 → 类别 → 动作"的映射表,查询结果回来后自动归类,把不同类别路由到不同的处理队列:付款方问题直接给前台提示,配置问题触发告警,时限问题进入延迟复核,商户自身问题进开发工单。

// 回执码分类与路由(Node.js 示例,映射表按你的网关文档维护)
const CODE_CLASS = {
  AC01: 'PAYEE_CONFIG', AC04: 'PAYEE_CONFIG', AC06: 'PAYEE_CONFIG',
  AM02: 'PAYER',        AM04: 'PAYER',        AM05: 'DUPLICATE',
  AG01: 'RISK',         AG03: 'RISK',         RR04: 'RISK',
  TM01: 'TIMEOUT',      AB03: 'TIMEOUT',      AB05: 'TIMEOUT',
  AB06: 'SYSTEM',       AB07: 'SYSTEM'
};

const ACTION = {
  PAYER:        (o) => notifyCashier(o, '付款方余额或限额问题,请顾客更换钱包或方式重试'),
  PAYEE_CONFIG: (o) => alertOps(o, 'P1', '收款账户配置或状态异常,所有交易可能受影响'),
  RISK:         (o) => alertOps(o, 'P2', '风控拦截,联系收单机构确认商户类别与规则'),
  TIMEOUT:      (o) => deferReview(o, '等待清算终态或冲正,禁止让顾客重复支付'),
  SYSTEM:       (o) => switchChannelAndDefer(o),
  DUPLICATE:    (o) => openDevTicket(o, '订单号或幂等键疑似重复生成'),
  UNKNOWN:      (o) => openDevTicket(o, '未知回执码,补充映射表')
};

async function handleFailed(order) {
  const cls = CODE_CLASS[order.clearing_reason_code] || 'UNKNOWN';
  await ACTION[cls](order);
  await auditLog.write({ order: order.out_trade_no, code: order.clearing_reason_code, cls });
}

三个真实场景的复盘

场景一:午高峰某门店连续几笔扫码都提示失败,收银员以为网络问题让顾客换现金。事后查网关,原因码全是账户类,根因是我们前一天在网关后台更换了结算账户,新账户信息里有一位数字填错。这类问题的教训是,配置类的码一出现就应该触发全局告警,而不是等运营一笔一笔报上来。场景二:顾客出示付款成功截图,后台却没有订单。查询接口显示网关侧状态是成功,回调日志里有一条验签失败记录,原因是我们那天刚上线的新版本改了参数排序逻辑。这根本不是清算失败,是我们自己的回调处理有 bug,交易资金早已清算完成。场景三:某个周末凌晨一批订单停在处理中,原因码是接收方处理超时。对照收单机构的维护公告,正好是系统维护窗口,这种情况的应对可以参考QRPH 系统维护期间商户收款怎么办:当时不做任何干预,维护结束后部分交易自动变为成功,其余自动冲正,次日对账全部对平。如果当时让顾客重付,反而会制造一堆需要退款的重复支付。

三种接入方式下,你能看到多少回执信息

回执码能不能看到、看到多细,和你的接入方式直接相关。这也是不少商户排查困难的根源:不是不会排查,而是根本拿不到信息。

对比维度仅持有静态 QRPH 码,靠银行流水对账通过持牌支付网关接入 QRPH自建系统直连收单机构
能看到的失败信息基本看不到,只能看到成功入账的流水网关订单状态 + 透传的清算原因码(视网关能力)完整的清算报文与原因码
排查工具银行 App 或网银流水,人工比对订单查询接口、回调日志、商户后台自建监控与报文日志
定位责任方的能力弱,只能区分"到了"和"没到"中到强,取决于网关是否透传原因码强
开发与维护成本几乎为零一次对接,网关负责通道维护高,需要自己处理报文、密钥、合规与认证
适合的商户单店、低频、不需要系统记账绝大多数有系统的商户大型机构或自身就是持牌支付主体

对大多数商户来说,中间这条路是现实选择。挑网关时有一个很具体的技术问题值得在签约前问清楚:失败交易的清算层原因码是否原样透传给商户?有的网关只给一个笼统的"支付失败",那你后面所有的分类逻辑都无从谈起。关于 QRPH 接口对接的其他细节,可以参考QRPH 商户 API 接入怎么做。

还有一件事要放在排查之前说清楚:无论你走哪种接入方式,承接 QRPH 资金清算与结算的机构都应当是持有 BSP 颁发的 OPS 或 EMI 资质的主体。原因码能不能透传、冲正能不能自动完成、争议能不能有据可查,归根到底取决于资金链路上的每一方是否都是受监管的参与机构。如果某个服务商连自己的清算路径都说不清楚,排查方法再好也没有落脚点。

把失败做成可观测的:预防比排查更省

排查是事后动作,真正省人力的是事前把失败变得可观测。我们做了四件事。第一,所有网关返回和回调的原始报文先落盘再解析,保证任何时候都能回溯原始原因码,而不是只留下自己解释过的状态。第二,按类别而不是按单笔设告警阈值:付款方问题是常态,不告警;配置类问题出现一笔就告警;时限类和系统类问题在短时间内聚集到一定数量才告警,避免噪音。第三,给运营做一个只有三列的看板:订单号、失败类别、建议动作,屏蔽掉技术细节。第四,每次对账时把"网关成功、本地失败"和"本地成功、网关失败"两类单边账单独列出来,它们几乎都对应商户自身的代码或配置问题,是系统质量最好的体检指标。关于争议和退款这条后续链路,可参考QRPH 争议处理怎么做。

常见问题

付款人显示支付成功,商户后台没有记录,算清算失败吗?

多数情况下不算。这种现象通常说明清算已经完成,问题出在接收方之后的环节,最常见的是商户回调没有正确处理。先查网关侧订单状态,再查回调日志,一般能很快定位。

清算层原因码和网关返回的错误码是一回事吗?

不是。前者来自实时清算网络,采用 ISO 20022 体系的标准化原因码;后者由网关或收单机构自行定义,描述的是业务校验结果。排查时要分清你看到的是哪一套。

订单长时间停在处理中,可以让顾客再扫一次吗?

不建议。处理中意味着清算层可能还在等待终态或准备冲正,此时重复支付很容易造成双重扣款。正确做法是查询订单终态,把这笔放进待复核队列,等待自动冲正或对账确认。

怎么判断失败是个案还是全量故障?

看原因码类别和集中度。账户类、商户状态类的码一旦出现,通常会影响所有交易,属于全量故障;余额不足、付款人限额这类则是分散的个案。按类别设告警就是为了自动做这个区分。

网关不透传清算原因码怎么办?

先确认是网关能力不支持还是默认未开启,很多网关可以在商户后台或通过申请打开透传。如果确实不支持,排查时只能依赖网关客服,这会显著拉长处理时间,是选型时应当提前问清楚的问题。

静态码和动态码的失败排查有区别吗?

有。动态码每笔交易带独立订单号,可以精确到单笔定位;静态码通常只能靠金额和时间去匹配银行流水,失败信息基本不可见。对有排查需求的商户,动态码或网关接入是更合适的方式。

冲正和退款是一回事吗?

不是。冲正是清算层对未完成交易的自动撤销,付款人资金通常原路返回,商户不需要操作;退款是对已成功交易的主动退回,需要商户发起。把两者混在一起会导致重复退款。

写在最后

QRPH 跨行清算失败不是一个问题,而是分布在付款方、清算层、收款方、网关和商户系统五个层面的一组问题。把回执码按层归类,再对应到"通知付款人、改配置、等待终态、修代码"四种动作,排查就会从凭经验猜变成按规则走。如果你手上正好有一批看不懂的原因码,或者想对一下你们的分类映射表,欢迎通过 Telegram 联系@LouisSMARTPAY,或邮件联系[email protected],把网关返回原文发过来我们一起看。

相关推荐