微信支付商家转账到个人小程序接口实战指南
随着小程序生态的不断发展,很多企业和商家都有一个常见需求:如何从商家账户安全、合规地向用户发放资金?比如发放活动奖励、推广佣金、用户返现、分销结算等。
微信支付官方提供了 商家转账到零钱(小程序场景)接口,能够帮助企业实现这一功能。本文将结合 PHP 代码示例,带大家了解如何调用该接口。
为什么需要小程序转账?
在很多实际业务中,资金发放是必不可少的一环,例如:
用户激励:完成任务后直接发现金红包到用户零钱;
分销/返利:按比例将佣金结算到个人账户;
补贴/退款:活动补贴、订单差价等直接发放;
奖励发放:抽奖、签到活动即时兑现。
相较于传统的人工转账,微信官方 API 更安全、自动化、可追溯,也能减少财务人工操作风险。
接口介绍
接口地址:
POST https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/transfer-bills
核心要点:
需要商户号(mchid)、小程序 appid、API证书和私钥;
请求必须使用 SHA256 with RSA 加签,保证安全性;
金额 >= 2000 元时必须填写收款人姓名,并且使用平台公钥加密;
支持自定义业务单号、转账备注、场景 ID 等。
PHP 示例代码
下面是一段完整的 PHP 实现,包含签名、加密和请求逻辑。
<?php
namespace wechat;
class WxPayMiniTransfer
{
// 配置参数
private $mchid = ''; // 商户号
private $appid = ''; // 小程序APPID
private $certPath = ''; // 商户证书路径
private $keyPath = ''; // 商户私钥路径
private $wechatpaySerial = ''; // 微信支付平台证书序列号
private $mch_serial = ''; // 商户证书序列号
private $apiUrl = 'https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/transfer-bills';
/**
* 发起商家小程序转账
* @param array $transferInfo 转账信息数组
* @return array
* @throws \Exception
*/
public function __construct()
{
$config = config('wechat');
$this->mchid = $config['mch_id'];
$this->appid = $config['app_id'];
$this->certPath = $config['cert_path'];
$this->keyPath = $config['key_path'];
$this->wechatpaySerial = $config['wechatpay_serial'];
$this->mch_serial = $config['mch_serial'];
}
public function createMiniTransfer(array $transferInfo)
{
$data = [
'appid' => $this->appid,
'out_bill_no' => $transferInfo['out_bill_no'],
'transfer_scene_id' => $transferInfo['transfer_scene_id'],
'openid' => $transferInfo['openid'],
'transfer_amount' => $transferInfo['transfer_amount']*100,// 转账金额(分)
'transfer_remark' => $transferInfo['transfer_remark'],
//'notify_url' => $transferInfo['notify_url'],
'user_recv_perception' => $transferInfo['user_recv_perception'],
'transfer_scene_report_infos' => $transferInfo['transfer_scene_report_infos']
];
if($transferInfo['transfer_amount']>=2000){
if(empty($transferInfo['user_name'])){
throw new \Exception( '明细金额大于等于2000时,收款人姓名必须填写');
}
$data['user_name']= $this->encryptUserName($transferInfo['user_name']);
}
// 1. 构建请求Body
$body = json_encode($data, JSON_UNESCAPED_UNICODE);
// 2. 生成随机串和时间戳
$nonce = $this->generateNonce();
$timestamp = time();
// 3. 生成签名
$method = 'POST';
$url = '/v3/fund-app/mch-transfer/transfer-bills'; // 请求的绝对路径
$signatureMessage = $method . "\n" .
$url . "\n" .
$timestamp . "\n" .
$nonce . "\n" .
$body . "\n";
// 使用商户私钥对签名串进行SHA256 with RSA签名
$signature = $this->signMessage($signatureMessage);
$signatureBase64 = base64_encode($signature);
// 4. 构建Authorization请求头
$token = sprintf('WECHATPAY2-SHA256-RSA2048 mchid="%s",nonce_str="%s",signature="%s",timestamp="%s",serial_no="%s"',
$this->mchid,
$nonce,
$signatureBase64,
$timestamp,
$this->mch_serial
);
//测试检验你的小程序和商户的密钥等设置是否正确
// curl -X POST https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/transfer-bills \
// -H "Content-Type: application/json" \
// -H "Authorization: WECHATPAY2-SHA256-RSA2048 mchid=\"你的商户号\",nonce_str=\"243ea1a0\",signature=\"HzVHaqu1fau2U4MYbL8PR0uFh7vxGhoEHRA9Y/zOFpOO2u8MdMBx7NLCtYxKup9Ey+I2CufR0iDWycCmGt+CPU6EyQ7PiwFDqHHjP/CnYxwoko5POUwMmXkqORQw6QmUEF5RInVXEDnOa8TCNzS/64PiMsNFItvLSVM8HJxeWU9Aywka88yizr67hvKpw0NOaj+Rte44g36k9UvMK4yKH3rxr4A6gPFFVaObrPMQ4U3JxGl+euBJmiWy1gi8Yc2UVQ7dhUxzVVXrXmigEsjfakaFZW6y7dU34Q3GQxddeB1XbDtnG1vcJ+CDOMo4ET2RUXr0JZD+VgIw5tD16ealJQ==\",timestamp=\"1756569416\",serial_no=\"245032232472480232664006076861880199408114685090\"" \
// -H "Wechatpay-Serial: 350853A73D8C3FD184F0152174F4199EB2DF2D22" \
// -d '{"appid":"你的小程序appid","out_bill_no":"202507262216578774","openid":"oXJi25S_ikttPhn3vKy_9rJoNNZs"}'
//openssl x509 -in apiclient_cert.pem -noout -serial 查询商户证书序列号
//openssl x509 -in apiclient_cert.pem -noout -text | grep -o 'CN=[0-9]*' | sed 's/CN=//' 根据证书查询商户号
// 5. 设置HTTP头并发送请求
$headers = [
'Content-Type: application/json',
'Accept: application/json',
'User-Agent: 你的小程序名字',
'Authorization: ' . $token,
'Wechatpay-Serial: ' . $this->wechatpaySerial // 添加微信支付平台证书序列号
];
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $this->apiUrl,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $body,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYPEER => true,
CURLOPT_SSL_VERIFYHOST => 2,
CURLOPT_SSLCERT => $this->certPath,
CURLOPT_SSLKEY => $this->keyPath,
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
curl_close($ch);
if ($error) {
throw new \Exception("cURL Error: " . $error);
}
// 6. 处理响应
$result = json_decode($response, true);
if ($httpCode >= 200 && $httpCode < 300) {
return $result;
} else {
throw new \Exception(sprintf('Request failed. HTTP Code: %d, Response: %s', $httpCode, $response));
}
}
/**
* 生成随机串
*/
private function generateNonce()
{
return sprintf('%08x', mt_rand(0, 0x7fffffff));
}
/**
* 对消息进行签名
*/
private function signMessage($message)
{
$privateKey = $this->getPrivateKey();
openssl_sign($message, $signature, $privateKey, 'sha256WithRSAEncryption');
return $signature;
}
/**
* 加载商户私钥
*/
private function getPrivateKey()
{
$key = file_get_contents($this->keyPath);
if (!$key) {
throw new \Exception("Failed to load private key: {$this->keyPath}");
}
$privateKey = openssl_get_privatekey($key);
if (!$privateKey) {
throw new \Exception("Failed to parse private key");
}
return $privateKey;
}
/**
* 加密敏感信息(用户名)
* 需要使用微信支付平台证书进行RSA加密
*/
public function encryptUserName($userName)
{
$encrypted = '';
$result = openssl_public_encrypt(
$userName,
$encrypted,
$this->wechatpaySerial,
OPENSSL_PKCS1_OAEP_PADDING
);
if (!$result) {
throw new \Exception("加密失败: " . openssl_error_string());
}
// 4. 返回Base64编码结果
return base64_encode($encrypted);
}
}
$config = config('wechat');
核心步骤包括:
生成签名串(method、url、timestamp、nonce、body);
使用商户私钥进行 SHA256withRSA 签名;
拼接 Authorization 头部;
通过 cURL 发起 HTTPS POST 请求;
解析返回结果,判断是否转账成功。
调用示例:
$transfer = new WxPayMiniTransfer();
$transferData = [
'out_bill_no' => $withdraw['order_no'], // 商户转账单据号
'transfer_scene_id' => '1005', // id=1005 佣金报酬
'openid' => $withdraw['openid'], // 用户openid
//'user_name' => $withdraw['real_name'], // 用户名(需要加密)
'transfer_amount' => $withdraw['amount'],
'transfer_remark' => '佣金奖励', // 转账备注
'user_recv_perception' => '劳务报酬', // 用户领取感知
'transfer_scene_report_infos' => [
[
'info_type' => '岗位类型',
'info_content' => '佣金奖励'
],
[
'info_type' => '报酬说明',
'info_content' => '佣金奖励'
],
]
];
$result = $transfer->createMiniTransfer($transferData);
if ($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS') {
// 更新状态为成功
$withdraw->save([
'status' => 'agree',
'wechat_billno' => $result['payment_billno'] ?? '',
'handle_time' => time(),
'memo' => '提现成功'
]);
//增加金额记录
UserMoneyLog::log($withdraw['user_id'], $withdraw['amount'], '余额提现', 'withdraw');
$this->success('提现成功');
} else {
// 微信返回失败
$withdraw->save([
'status' => 'fail',
'handle_time' => time(),
'memo' => $result['err_code_des'] ?? '微信返回失败: ' . json_encode($result),
]);
$this->error('提现失败:' . $result['return_msg']);
}
注意事项
证书管理:需要上传商户 API 证书、私钥,并在配置中填入对应序列号;
敏感信息加密:收款人姓名必须使用 微信支付平台证书公钥加密,而不是直接传输明文;
错误处理:接口返回非 2xx 状态时,需要记录日志,便于排查;
幂等性:业务单号
out_bill_no
必须唯一,避免重复转账;安全合规:确保资金发放符合业务和监管要求,避免违规用途。
应用场景举例
电商返现:商家活动奖励自动结算到用户零钱;
社交平台:创作者分成收益定期结算;
出行/生活服务:司机、骑手补贴自动到账;
企业内部:员工激励金、奖金发放。
总结
微信小程序转账接口为商家提供了一个 安全、自动化、灵活 的资金发放渠道。通过 API 调用,商家可以将用户激励、返利、补贴等资金高效发放到个人零钱账户,不仅提升了用户体验,也降低了财务操作成本。
如果你正准备在小程序或平台业务中增加 奖励结算、返现 功能,那么微信支付的 商家转账接口 将是一个非常合适的解决方案。
发表评论 取消回复