那天我打开商户后台,发现昨天有七笔订单状态是“渠道受理成功”,但结算列表里只有六笔。差了那一笔是一条微信小程序支付,通道返回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
通道侧把商户状态从冻结改为正常后,那笔丢掉的结算又回来了,金额一分不差。对账消息显示补结成功。