那天我打开商户后台,发现昨天有七笔订单状态是“渠道受理成功”,但结算列表里只有六笔。差了那一笔是一条微信小程序支付,通道返回sub_code=SUCCESS,金额也没错。开始以为是回调丢了。

结果日志里回调记录好好躺着,验签也是通过。真正的问题出在商户资质。

那笔订单的资金状态显示“冻结待审”。通道后台的商户详情页里,营业执照有效期已经过期16天。微信侧风控没有拒交易,只是把待结算资金先挂起,发了一条站内通知。通知标题是“商户资质异常”,不太显眼,躺在未读列表第三页。

前置条件其实很简单:商户进件时提交的证照必须清晰、在有效期内,结算账户名与法人一致。三类资料——营业执照、法人身份证、开户许可证或银行账户正面。少一样,通道审核就会卡在机审队列里,但机审不通过不一定立刻阻断交易,它会放一部分小额交易进来,然后冻结资金。这个设计很让人头疼。

所以第一步不是查回调,而是核对商户状态。

SELECT mch_id, review_state, license_expire FROM mch_info WHERE mch_id=1102;

这里试了两种方法。第一种是直接重新提交新执照,让通道重新机审。第二种是先把费率调成T1,想绕过冻结。后来才发现第二种完全没用,风控挂起不看结算周期。

这事后来被我整理进一份内部文档,名字就叫聚合支付合规经营指南。不夸张,照着做能少冻好几笔。

商户资质补起来比想象中细

file license.jpg bank_card.pdf

参数配置里有几个容易留坑的地方

"mch_type": 0,
"settle_mode": "T1",
"rate": 0.006

还有一个点:网站支付功能实现方案里最容易漏的不是支付按钮,而是回调鉴权。很多人在本地联调时图快,把验签注释掉,上线忘记恢复。通道的异步通知如果没有验签,攻击者可以伪造success通知,把未支付订单改成已支付。验签函数本身不复杂。

sign = hmac_sha256(sorted_query, secret_key)
if sign != received_sign: return "FAIL"

如果你也遇到回调验签一直失败,先查参数排序再看密钥末尾换行符,多半是商户号对应密钥不匹配的问题。特别是从文档里复制密钥,经常会带一个看不见的换行。

回调IP白名单和账户验证

curl -s https://api.example.com/notify_ips | jq -r '.ips[]'

结算账户验证同样不能跳。商户换了新执照,开户许可证没换,账户名对不上。通道会发起一笔小额打款,金额几毛钱随机,让商户回填。

SELECT verify_id, amount, status FROM settle_verify WHERE mch_id=1102;

商户问的那些问题

个人站长合法收款方案的核心不是绕过监管,是找有资质的服务商,同时保证自己的业务场景真实。卖课、卖会员、卖文档都行,但不要做代收款、预支、刷流水。这些场景很容易把商户号送进风控名单。

那次冻结的商户,后来重新提交了营业执照和新的开户许可证。通道侧机审过了,人工复核发了一次补充说明要求。我们在后台备注里写了实际经营内容,还上传了最近三个月的银行流水。第二天通道状态变成“正常”。

上线前的验证动作

curl -X POST -d "order_id=TEST2026032201" http://127.0.0.1:8080/pay/notify

然后做并发测试。不是在现网压,是预发环境,100个请求10个并发,看响应时间和超时率。

ab -n 100 -c 10 http://127.0.0.1:8080/pay/create

通道侧把商户状态从冻结改为正常后,那笔丢掉的结算又回来了,金额一分不差。对账消息显示补结成功。