SMARTPAY

GCash 原生支付接入怎么做?API 对接、验签与生产切换完整流程

一、什么叫「原生接入」,和「三方跳转」有什么不一样

菲律宾商户在选 GCash 收款方案时,第一件要分清的事就是「原生」还是「跳转」。这两条路的差别不只是技术,更是客单价、客诉率和拒付率的差别。作为在马尼拉本地经营多年的中国技术负责人,我踩过这两种坑,下面把差异摊开讲清楚。

原生接入指商户后端直接调用聚合网关的 API,拉起 GCash 客户端支付授权,用户在自家 App/H5 里全程完成付款,收银台是自家的。三方跳转则是把用户丢到收银台域名,由第三方页面完成扫码或输入,回来后再通过回调告知结果。

维度原生接入三方跳转收银台
用户体验不跳出商户品牌页,流畅会跳到陌生域名,弃单率偏高
技术工作量需要处理签名/回调/对账只需生成一个跳转 URL
可控字段订单号、金额、备注、扩展参数全可自定义受收银台模板限制
合规责任商户方承担更多参数校验大部分校验在网关侧完成
适合场景自有 App、有开发团队、订单量较大MVP 阶段、H5 落地页、快速试跑

再补一句:很多技术负责人第一次评估时,只看「跳转两天就能上」的表面便利,结果客单价高、复购强的业务上线两周就发现跳出型收银台弃单率明显高于自家 App 页,回头再改原生已经晚了。选型这一步值得跟业务负责人一起坐下来算账,不要只让技术拍板。

二、对接前要准备的六样东西

不要还没拿全材料就急着写代码,不然联调阶段会来回踢皮球。经验清单:

  1. 商户号 merchant_id(网关分配)
  2. API 密钥 api_key 和签名密钥 secret_key(两把不同的钥匙,别混用)
  3. 结算银行账户信息(菲律宾本地对公户)
  4. 回调地址 notify_url(必须是公网 HTTPS)
  5. 白名单出网 IP(网关侧会做 IP 校验)
  6. 联调用的沙箱账号(测试 GCash 号 + 测试金额区间)

关于商户号申请路径,可以参考支付 API 对接教程里的资料清单,以及GCash 商户号申请那篇的行业资质要求。

三、原生下单接口:一段真 curl 请求样例

下单接口的核心是「参数拼装 + 签名 + POST JSON」。以下是典型的 GCash 拉起支付请求,字段名各家网关略有出入但结构一致:

curl -X POST https://apix.paysmartph.com/api/pay/create \
  -H "Content-Type: application/json" \
  -H "X-Merchant-Id: M20260001" \
  -d '{
    "merid": "M20260001",
    "tno": "ORDER20260925001",
    "amt": "1288.00",
    "channel": "GCASH",
    "subject": "Order Payment",
    "notify_url": "https://shop.example.ph/api/pay/notify",
    "return_url": "https://shop.example.ph/order/success",
    "client_ip": "203.0.113.10",
    "nonce": "a8f3d2c1b0e9",
    "timestamp": 1758787200,
    "sign": "7A2E9F1C4B6D8E0A2F4C6B8D0E2F4A6C"
  }'

返回体一般会带回 pay_url(H5 拉起链接)或 deeplink(移动端唤起 GCash App 的 URL Scheme)。你只需要把这个链接扔给前端,由用户在 GCash App 里确认扣款即可。

四、HMAC 验签怎么做才靠谱

签名是原生接入最容易出问题的一环。踩坑排名前三:字段排序不一致、空字符串是否参与签名、字符编码差异。给一段可直接抄的 Node.js HMAC-SHA256 验签例子:

const crypto = require('crypto');

function verifySign(payload, secretKey) {
  // 1. 抽出 sign 字段本身,不参与签名
  const { sign, ...rest } = payload;

  // 2. key 按 ASCII 升序排序
  const keys = Object.keys(rest).sort();

  // 3. 拼成 key1=value1&key2=value2 形式,空值跳过
  const raw = keys
    .filter(k => rest[k] !== '' && rest[k] !== null && rest[k] !== undefined)
    .map(k => `${k}=${rest[k]}`)
    .join('&');

  // 4. HMAC-SHA256 → 转大写十六进制
  const expected = crypto
    .createHmac('sha256', secretKey)
    .update(raw, 'utf8')
    .digest('hex')
    .toUpperCase();

  return expected === sign;
}

验签这一步必须放在回调处理的最开头,任何数据库操作、任何日志落库都要在验签通过之后再做,否则可能被伪造回调触发订单状态漂移。回调接收后的幂等、去重、对账处理,建议翻一下商户回调 notify_url那篇的踩坑清单。

SMARTPAY 是持 BSP OPS/EMI 双牌照的独立支付网关,提供 GCash、Maya、QRPH 等本地通道对接服务,非 GCash 官方主体。牌照使得回调与结算全链路受 BSP 监管,商户对账追溯有据。

五、回调处理与幂等设计

GCash 网关的成功回调可能重复推送(网络重试机制),因此回调处理必须做幂等。推荐做法:

  • 用 tno(商户订单号)做唯一键,数据库加唯一索引
  • 处理前先查订单当前状态,若已是「支付成功」则直接返回 SUCCESS
  • 状态机严格化:待支付 → 支付中 → 支付成功/失败,不允许倒退
  • 回调应答体固定用 SUCCESS 字符串,避免 JSON 结构差异
  • 业务侧再挂一个「主动查单」任务,兜底那些回调完全丢失的场景
  • 回调处理耗时控制在秒级以内,超时会被网关判为失败继续重试,反而放大压力
  • 回调入库先落原始报文,再触发业务逻辑,方便事后追溯网关侧的原始参数

另有一个容易被忽略的坑:业务方在测试期把回调地址临时改到内网穿透工具(比如 ngrok),上线后忘了切回自家域名,结果生产订单全部走到废弃地址上,只能靠对账文件手动补单。上线前一定要人工确认回调 URL 是线上真实域名。

关于对账,如果业务量到了每天几千单以上,一定要建立自动对账流程,拿网关的对账文件与自家订单库对齐,而不是靠客服人肉查。商户对账那篇里介绍了对账文件字段与差异处理的常见路径,可以借鉴。

六、沙箱到生产的完整检查清单

沙箱阶段必测的七个异常路径

沙箱阶段要把每个异常路径都跑一遍,不要只跑 happy path。生产上线后再补测,故障成本会翻几倍:

  1. 金额小数位数(有的网关只接受两位小数)
  2. 订单号重复提交是否返回相同 pay_url
  3. 用户取消支付后的回调形态
  4. 超时未支付订单的关单机制
  5. 回调签名故意错乱一位,自家验签能否拦截
  6. 大额限额单笔触发风控时的报错码
  7. 并发下单同一个 tno,数据库唯一索引是否兜住

再补一条我们内部会强制执行的规则:沙箱阶段的所有测试用例必须转成自动化脚本,不要只留在人工回归清单里。因为后续每一次网关侧升级都要跑一遍回归,人肉测试成本高又容易漏,自动化跑一遍几分钟出结果。

从沙箱切到生产的逐项 checklist

沙箱通过不等于生产没事。生产切换前逐项过一遍,这是我们内部的标准流程:

  • 切换 base_url:从 api-sandbox 换到 apix 域名
  • 换密钥:沙箱密钥销毁,生产密钥用密钥管理服务加密存储,不进 Git
  • 回调 URL 走线上域名,HTTPS 证书有效期检查
  • 出网 IP 报给网关侧加白名单
  • 数据库连接池扩容,回调峰值不会打挂
  • 接入监控告警:回调延迟超阈值、验签失败率异常、订单成功率骤降都要报警
  • 先跑小额真实订单,人肉核对到账、结算周期与商户对账单,确认无误后再放量

结算周期这一步别小看,如果对通道到账节奏还有疑问,可以先看QRPH 手续费与结算做横向对照,再结合自家现金流做决策。合规红线部分,BSP 合规那篇讲了持牌网关的监管框架,建议开发前通读一遍。

七、常见问题 FAQ

GCash 原生接入必须有菲律宾本地公司吗?

官方直连 GCash for Business 一般要求本地实体;通过持牌支付网关做原生对接,资料门槛会相对精简,具体以网关侧的审核结论为准,不能一概承诺。

H5 页面能不能实现原生体验?

可以。H5 场景下网关会返回一个 pay_url,浏览器打开后 GCash App 通过 deeplink 唤起完成扣款,再回跳回商户页面,用户不需要手动切换 App。

回调没收到怎么办?

先自查三点:回调 URL 是否公网可达、是否被 CDN/WAF 拦截、服务器是否返回了 SUCCESS。三点排除后再联系网关侧拉推送日志。同时建议把「主动查单」定时任务作为兜底,不要单点依赖回调。

签名总是失败,怎么定位?

九成是拼串顺序或空值处理不一致。把网关给的原始拼串日志和自己的日志逐字符比对,一目了然。另外注意 timestamp 是数字类型还是字符串类型,Boolean 类型如何序列化。

沙箱能测多久?

没有统一时限,只要商户资料在审批中,沙箱账号一般都可用。建议不要过度依赖沙箱,尽早申请生产上线,拿真实小额单验证全链路。

原生接入的技术投入大概多久?

一个熟悉 HTTP+HMAC 的后端工程师,从拿到文档到跑通首笔沙箱订单大约需要几个工作日;完成幂等、对账、监控、异常路径覆盖再叠加一段联调时间,不同团队差异较大。

可不可以同时对接 GCash + Maya + QRPH?

可以,而且强烈建议这么做。多通道路由能显著降低单一通道风控中断带来的收款损失。SMARTPAY 一次接入即可拿到 GCash、Maya、QRPH 等主流菲律宾支付通道能力,具体路由策略可以在商户后台自定义。

接口返回的错误码怎么处理才对?

建议把错误码分成三档:业务错误(比如金额格式不对)直接抛前端提示、通道临时错误(比如上游繁忙)进入自动重试队列并做退避、致命错误(比如商户号无效)则触发内部告警而不是让用户看到。分层处理才能既保护用户体验又不会淹没运维视野。

八、下一步与联系方式

原生接入不是难事,难的是把幂等、对账、监控、异常路径这些「不出问题时没人在意」的地方做扎实。真正的成本节省来自减少客诉与人工补单,而不是接口本身。如果你已经理清了原生接入的技术要点,想尽快落地菲律宾本地收款,欢迎联系 SMARTPAY 拿沙箱账号和对接文档:📩 [email protected] | Telegram @LouisSMARTPAY

相关推荐