PesaBridge
全部洞察
技术Jun 2026 · 11 分钟阅读

推送支付详解:把 STK 推送做对

商户发起的请求如何变成客户手机上的 PIN 输入提示,以及如何让它即时、安全且幂等。失败时也不会重复扣款。

T
The PesaBridge team · Engineering

推送支付是每个移动货币客户都熟悉到不假思索的流程。商户请求付款,客户手机上弹出提示,客户输入 PIN,交易完成。在较早普及移动货币的市场,这是使用最广泛的支付方式,而且感觉毫不费力。这种轻松感背后,是大量为了"隐身"而努力工作的工程设计。任何一环出错,便利就会变成重复扣款、卡住的付款,或者商户为一笔从未到账的钱交付了货物。

下面介绍提示背后实际发生的事情,以及如何让它即时、安全、绝不重复扣款。

提示到达的两种方式

"弹出提示"背后有两种机制,它们的覆盖范围和故障模式不同,因此很重要。

经典机制是 SIM 应用工具包(STK):运行在 SIM 卡本身上的代码,因此能在没有安装任何应用的普通功能机上推送安全的 PIN 输入提示。最早的移动货币系统正是借助 STK 覆盖了所有人:菜单和 PIN 输入都由 SIM 卡通过网络驱动,运行在别无他物的硬件上。现代机制是应用推送:向智能手机应用发送通知,打开确认界面。两者殊途同归:客户授权后,扣款进入其生命周期。值得构建的平台会同时支持两者,因为客户群体两种手机都有。

扣款是一个状态机

推送支付中最重要的理念是:扣款不是一个事件,而是一个状态机,具有明确、定义清晰的状态和转换。把它当作"发出即忘"的调用,是大多数生产事故的根源。状态大致如下:

  • 处理中:商户已发起扣款;提示已推送;系统正在等待客户。
  • 已授权:客户已输入 PIN 并确认;系统已检查余额和限额,正在提交资金变动。
  • 已完成:账本已记录平衡的分录;资金已转移;商户可以交货。
  • 已拒绝 / 已过期 / 失败:客户拒绝、提示超时或某项检查失败;没有资金变动,扣款被干净地关闭。

每笔扣款在任何时刻都恰好处于其中一个状态,并且只能沿着定义好的转换移动。这不是官僚主义,而是让流程可推理、可恢复的关键。出问题时,要问的永远是"这笔扣款处于什么状态,哪个转换卡住了?",这是一个有答案的问题,而不是一声无奈的叹息。

商户如何得知结果

商户系统需要知道扣款是否完成:以便打印小票、放行货物、更新订单。有两种获知方式,它们之间的差别,就是笨拙集成与利落集成之间的差别。

  1. 轮询。商户反复询问状态接口:"好了吗?"这能用,但浪费且滞后:轮询太频繁会压垮 API;太稀疏则客户只能站在收银台前干等。
  2. Webhook。扣款状态一变化,平台立即向商户推送一个已签名的回调。商户在瞬间得知结果,没有浪费的调用,并获得一个可直接处理的清晰事件。这才是正确的基础机制,构建良好的平台会将其设为默认方式,并以轮询作为后备。

是什么让它值得信赖

有三项特性能把一个能跑通的演示,变成商户可以赖以经营的系统。

幂等性:重复扣款的克星

网络会重试。如果商户的"创建扣款"请求超时后被重新发送,就绝不能创建第二笔扣款。每个创建扣款的请求都带有一个幂等键;平台记录该键,使用相同键的重复请求会返回原有扣款,而不是新建一笔。同样的规则也保护确认步骤。客户感受到的保证——"我只被扣了一次"——正是这项特性,它在资金变动的那一刻强制执行,而不是应用里一次侥幸的检查。

签名的 Webhook

Webhook 是一个不请自来的 HTTP 调用,到达商户服务器并声称某笔付款已完成。商户凭什么相信它?因为每个回调都有签名:使用只有平台和商户知道的共享密钥,对内容计算出的 HMAC-SHA256 签名。商户重新计算签名,拒绝任何不匹配的回调,这让伪造的"您已收款"回调对攻击者毫无用处。并且由于网络会出故障,Webhook 会以递增间隔重试,直到被确认接收,因此商户端的短暂中断不会丢失事件:它会被反复投递,直到商户服务器返回成功。

过期

未确认的扣款不能无限期挂着。如果客户没有输入 PIN 就离开了,扣款必须干净地过期,而不是作为一笔未结的负债留着,可能在一小时后莫名其妙地完成。一个有界且可预测的过期窗口,才能让商户看到的情况与客户保持一致。

区分真实系统与演示的边界情况

顺利路径(推送、确认、完成)只是工作中容易的那四分之一。有意思的故障都藏在缝隙里:

  • 客户已确认,但网络丢失了确认回执。扣款在平台上已是 completed,商户却没收到通知。Webhook 重试正是为此而设。商户的处理程序本身也必须是幂等的,这样重复投递的"已完成"事件不会导致货物发出两次。
  • 两次确认同时到达。重试的确认不能重复记账。幂等键和状态机共同保证第二次确认看到的是"已完成",而不是再次转移资金。
  • 扣款恰好在客户确认的同一时刻过期。状态机必须规定唯一的胜者:转换是原子的,因此扣款要么已授权,要么已过期,绝不会两者兼有,并且会明确告诉客户是哪一种。
  • 对账。日终时,每一笔 completed 扣款都必须对应一组平衡的账本分录和一条结算记录。由于扣款生命周期与账本绑定在一起——完成就是记账——对账是由结构保证的,而不是靠调查。

一个实例时间线

以下是商户向客户收取 1,250 杂货款时逐秒发生的事情。时间为典型值,并非保证。

时间发生了什么扣款状态
0.0 秒收银员输入客户号码和金额;收银台发送带幂等键的创建扣款请求处理中
0.3 秒平台验证商户和客户,并推送提示处理中
2–20 秒客户查看商户名称和金额,并输入 PIN处理中
+0.2 秒核心系统检查 PIN、余额和限额,并记录平衡分录已完成
+0.5 秒签名的 Webhook 到达商户;客户和商户收到确认已完成
稍后商户余额按其结算周期划入银行已完成,已结算

客户阅读和输入占据了大部分时间。平台所做的一切都远不到一秒,这就是为什么运作正常时体验感觉是即时的,而偶尔出现的慢步骤会立刻被察觉。

正确构建商户端

可靠的推送支付集成,有一半在商户系统里。一个好的 Webhook 处理程序应当:

  • 在信任内容中的任何信息之前,先验证签名。
  • 具备幂等性:同一事件的第二次投递不会改变任何东西。
  • 快速响应,把繁重工作放到之后处理,以免平台超时并进行不必要的重试。
  • 按扣款参考号匹配,绝不只凭金额和电话号码。
  • 如果在预期窗口内没有收到事件,回退到状态接口查询,而不是假定失败。
  • 记录收到的每一个事件,以便用记录回应争议。

选择过期窗口

过期时间是一种权衡。太短,正在找手机的客户还没确认扣款就已失效。太长,商户只能守着柜台上的货物等待,过时的提示还会在客户离开后才到达。大多数运营方为当面支付设置一到两分钟,远程请求(例如发给在家客户的账单)则更长。无论窗口多长,都要显示出来:知道提示持续一分钟的收银员,就知道何时该重试。

客户会注意到的细节

提示界面上的小选择,决定了客户是否信任它:

  • 显示商户的注册名称,而不是内部代码,让客户知道是谁在请求。
  • 在 PIN 输入框之前清楚显示金额和参考号。
  • 提供明确的拒绝选项,让没有预料到提示的客户可以拒绝,而不是置之不理。
  • 用文字和消息确认:包含商户、金额和参考号的回执,在屏幕上和短信中都提供。
  • 提醒注意意外的提示。欺诈者会发送提示,指望客户条件反射地批准;一句简短的"仅在您向该商户付款时才批准"即可降低这种风险。

一个生命周期,覆盖所有渠道

做对这件事的最后一环是:推送支付不应是一个在应用、收银台和 API 中分别接线的特例。它应该是一个由所有渠道驱动的统一扣款生命周期:客户扫描商户二维码、商户从 POS 终端发起扣款、合作伙伴调用开发者 API,创建的都是同一种扣款,经过相同的状态,记入同一个账本,发出相同的签名 Webhook。一次构建、正确构建,每个渠道都能继承这些保证。

推送支付、二维码还是收款号?

推送支付是向客户收款的三种常见方式之一。每种方式适合不同的场景:

方式由谁发起功能机可用最适合
推送支付商户可以,通过 SIM 卡提示商户知道金额的收银台和结账环节
二维码客户扫描不可以,需要智能手机应用智能手机客户较多的商店;小商贩使用静态码
收款号或缴费号客户输入可以,通过 USSD任何商户;通用的后备方式

商户能同时接受这三种方式时效果最好,而平台把它们视为通过不同途径到达的同一种付款。

围绕提示的欺诈

由于提示要求客户批准付款,它会吸引社会工程攻击。常见模式是:欺诈者触发提示,然后冒充服务提供商给客户打电话,诱导其批准。防御需要在多个层面进行:醒目显示请求商户经过验证的名称;限制商户在短时间内向同一号码发送提示的次数;监控提示大多被拒绝或被举报的商户;并反复告诉客户,服务提供商绝不会在电话中要求他们批准付款。商户入网审核同样重要,因为身份可追溯的已验证商户很难被用于欺诈。

衡量推送支付

指标为何重要
批准率客户批准的提示占比;突然下降意味着投递问题或客户困惑
批准耗时客户所用时间;耗时长说明界面不清晰或投递缓慢
过期率无人响应而失效的提示;据此调整过期窗口和对收银员的指导
Webhook 首次投递成功率商户无需重试即可可靠收到结果的程度
被举报的意外提示欺诈企图的早期信号

柜台之外:远程请求

当客户不在收银台前时,同样的机制也适用。学校可以向家长发送学费请求,公用事业公司可以请求缴纳账单,送货员可以在送达时请求付款。远程请求需要几项调整:更长的过期时间、对付款内容的清晰描述、请求方经过验证的名称,以及客户能从账单或消息中认出的参考号。状态机、签名和幂等性完全不变,这就是为什么一个统一的扣款生命周期可以同时服务收银台、账单和 API。

测试推送支付集成

在商户正式上线之前,请在沙箱中运行以下用例:

  • 分别批准、拒绝提示以及让提示过期,检查商户系统对每种情况显示的结果是否正确;
  • 用相同的幂等键发送两次相同的创建扣款请求,确认只存在一笔扣款;
  • 让商户的 Webhook 接口故障几分钟,确认其恢复后事件能够到达;
  • 发送一个签名错误的 Webhook,确认商户会拒绝它;
  • 尝试一笔超过客户限额的扣款,确认它被干净地拒绝;
  • 检查退款是否关联到原始扣款。

通过这些测试的集成,在最繁忙的日子里也会表现良好。

常见问题

如果客户没有数据连接怎么办?

基于 SIM 卡的提示通过移动网络工作,不需要数据。对于应用提示,没有数据的客户仍然可以通过 USSD 输入商户的收款号来付款。

商户能否在客户未批准的情况下扣款?

不能。只有客户用 PIN 授权后,扣款才会完成。商户可以发起请求;只有客户可以批准。

退款如何处理?

退款是一笔从商户返还给客户的新交易,并与原始扣款关联。原始扣款保留在历史记录中,双方都能看到支付了什么、退回了什么。

如果客户说已经批准,但收银台什么都没显示,收银员该怎么办?

等待结果,而不是再收一次款。收银台应使用参考号查询扣款状态。如果扣款已完成,结果会在片刻内显示;如果已过期,收银员可以放心发送新的提示。切勿把确认界面的截图当作付款凭证。

推送支付适合大额付款吗?

客户等级限额与其他任何付款完全一样适用,PIN 步骤也相同。对于大额商业付款,商户通常会把提示与账单参考号结合使用,以便双方能将付款与单据对应起来。

这样做,推送支付感觉是即时的,而且不可能重复扣款——不是因为从不出故障,而是因为每一种故障都有明确的状态、重试机制和回到一致性的路径。这正是 PesaBridge 在应用和开发者 API 中基于统一扣款生命周期所提供的能力。

关于商户收款的问题

静态二维码和动态二维码有什么区别?

静态码只需印制一次,由顾客输入金额。动态码针对每笔销售生成,金额已包含在内。

什么是推送支付(prompt-to-pay)?

商店输入顾客的手机号和金额,顾客在自己的手机上用 PIN 确认付款请求。

商店如何知道已收到付款?

付款一经确认,销售就会在商店的应用或收银台上确认,每笔付款都会显示在商户后台中。

接入渠道

无论客户如何支付,皆能触达。

一套钱包接入矩阵,按用户类别——消费者、代理或商户——跨每个渠道自由配置。

USSD
移动应用
网页
二维码
NFC
短信
POS

平台

钱包所需的一切——一套核心,您的品牌。

既有人人喜爱的消费级应用体验,又有专业金融平台的广度,还有一套无需编码即可运营全部功能的 SaaS 管理后台。

运作方式

以周计上线,而非以年计。

01

配置品牌与国家

在管理后台设置名称、标识、配色、货币、语言和 KYC 等级——应用即刻换肤。

02

接入支付通道

通过适配器接入银行、移动货币、卡组织、账单机构、税务和电信——只接入市场所需。

03

在应用、USSD 与网页上线

将自有应用上架双端商店,开通 USSD 短代码和网页门户——全部来自同一平台。

储值钱包 代理网络 商户收款 USSD 开发者 API 推送收款 KYC 等级 冲正 备付金分发 结算 签名 Webhook 白标 储值钱包 代理网络 商户收款 USSD 开发者 API 推送收款 KYC 等级 冲正 备付金分发 结算 签名 Webhook 白标

准备好上线您的钱包了吗?

预约演示,我们将为您搭建品牌、国家与通道——并带您走遍应用、管理后台与 API。

想直接沟通?请致电 +254 746 883809