为了在保证支付安全的前提下,带给商户简单、一致且易用的开发体验,我们推出了全新的微信支付APIv3接口。该版本API的具体规则请参考“APIv3接口规则”
备注:当前接口用于微信国内钱包
为了帮助开发者调用开放接口,我们提供了JAVA、PHP、GO三种语言版本的开发库,封装了签名生成、签名验证、敏感信息加/解密、媒体文件上传等基础功能(更多语言版本的开发库将在近期陆续提供)
测试步骤:
1、根据自身开发语言,选择对应的开发库并构建项目,具体配置请参考下面链接的详细说明:
• wechatpay-java(推荐)wechatpay-apache-httpclient,适用于Java开发者。
• wechatpay-php(推荐)、wechatpay-guzzle-middleware,适用于PHP开发者
注:当前开发指引接口PHP示例代码采用wechatpay-guzzle-middleware版本
• wechatpay-go,适用于Go开发者
更多资源可前往微信支付开发者社区搜索查看
2、创建加载商户私钥、加载平台证书、初始化httpClient的通用方法
@Before
public void setup() throws IOException {
// 加载商户私钥(privateKey:私钥字符串)
PrivateKey merchantPrivateKey = PemUtil
.loadPrivateKey(new ByteArrayInputStream(privateKey.getBytes("utf-8")));
// 加载平台证书(mchId:商户号,mchSerialNo:商户证书序列号,apiV3Key:V3密钥)
AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(
new WechatPay2Credentials(mchId, new PrivateKeySigner(mchSerialNo, merchantPrivateKey)),apiV3Key.getBytes("utf-8"));
// 初始化httpClient
httpClient = WechatPayHttpClientBuilder.create()
.withMerchant(mchId, mchSerialNo, merchantPrivateKey)
.withValidator(new WechatPay2Validator(verifier)).build();
}
@After
public void after() throws IOException {
httpClient.close();
}
3、基于接口的示例代码,替换请求参数后可发起测试
说明:
• 上面的开发库为微信支付官方开发库,其它没有审核或者控制下的第三方工具和库,微信支付不保证它们的安全性和可靠性
通过包管理工具引入SDK后,可根据下面每个接口的示例代码替换相关参数后进行快速测试
• 开发者如果想详细了解签名生成、签名验证、敏感信息加/解密、媒体文件上传等常用方法的具体代码实现,可阅读下面的详细说明:
1.签名生成
2.签名验证
3.敏感信息加解密
• 如想更详细的了解我们的接口规则,可查看我们的接口规则指引文档
1、微信支付分的相关配置参数在商户入驻的过程中都已经配置完成(前往查看配置相关内容),例如授权结果回调url、service_notify_url、测试白名单、免确认订单模式的权限等。
2、如果发现配置信息有误,请主动联系微信支付分运营同学协助修改,或者点击右侧导航栏进入在线技术客服进行技术咨询。
重点步骤说明:
步骤1 用户在商户侧下单,商户调用后台接口创建支付分订单,通过接口返回获得跳转微信支付分小程序进行订单确认的必填参数“package”
我们通过此接口来创建支付分订单:创建支付分订单API
步骤2 调用前端方法跳转至微信,让用户完成确认订单操作
我们通过以下前端方法可调起微信客户端(注意区分场景):
步骤3 用户确认订单完成,商户系统将收到确认订单回调通知,此时可为用户提供服务;
我们通过以下接口将用户确认订单信息回调通知给商户系统:
在用户确认订单过程中可能出现长时间未收到回调、用户确认失败等情况,商户可先通过后台接口查询订单状态:
根据查询到的订单状态结果,商户可决定是否需要取消当前订单,后台接口为:
步骤4 用户服务结束,商户通过后台接口完结支付分订单;
调用完结支付分订单API接口后,微信支付分就会发起对用户的扣款,但是在用户扣款过程中可能会出现一些特殊情况,下面列举了几种特殊情况以及对应的处理方法,供大家参考:
请求:
• 情况一:扣款过程中,发现扣款金额有误(注意:此时需要订单为“待支付”状态)
• 情况二:扣款过程中,用户通过其它方式完成了支付,希望微信支付分停止继续扣款
处理方法:商户调用同步服务订单信息接口将订单支付成功状态同步给微信支付分,微信支付分将停止继续扣款的操作
步骤5 收到用户扣款成功通知,业务流程结束
通过支付成功回调通知API接口可以获取到用户扣款成功的通知,同时,商户也可以根据情况通过查询支付分订单API接口主动查询扣款情况。
如遇到网络、服务器等原因造成无法正常接收扣款成功通知,一般有两种解决方法:
1.主动查单,通过查询支付分订单API 接口主动查询扣款情况
本文档展示了如何使用微信支付服务端 SDK 快速接入微信支付分产品,完成与微信支付对接的部分。
注意:
步骤说明:完成用户授权后,即可创建支付分订单,为用户提供服务了。
示例代码
public void CreateServiceOrder() throws Exception{
//请求URL
HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/payscore/serviceorder");
// 请求body参数
String reqdata = "{"
+ "\"out_order_no\":\"1234323JKHDFE1243252\","
+ "\"appid\":\"wxd678efh567hg6787\","
+ "\"service_id\":\"500001\","
+ "\"service_introduction\":\"某某酒店\","
+ "\"post_payments\": ["
+ "{"
+ "\"name\":\"就餐费用服务费\","
+ "\"amount\":4000,"
+ "\"description\":\"就餐人均100元服务费:100/小时\","
+ "\"count\":1"
+ "}"
+ "],"
+ "\"post_discounts\": ["
+ "{"
+ "\"name\":\"满20减1元\","
+ "\"description\":\"不与其他优惠叠加\""
+ "}"
+ "],"
+ "\"time_range\": {"
+ "\"start_time\":\"20091225091010\","
+ "\"end_time\":\"20091225121010\""
+ "},"
+ "\"location\": {"
+ "\"start_location\":\"嗨客时尚主题展餐厅\","
+ "\"end_location\":\"嗨客时尚主题展餐厅\""
+ "},"
+ "\"risk_fund\": {"
+ "\"name\":\"ESTIMATE_ORDER_COST\","
+ "\"amount\":10000,"
+ "\"description\":\"就餐的预估费用\""
+ "},"
+ "\"attach\":\"Easdfowealsdkjfnlaksjdlfkwqoi&wl3l2sald\","
+ "\"notify_url\":\"https://api.test.com\","
+ "\"openid\":\"oUpF8uMuAJO_M2pxb1Q9zNjWeS6o\","
+ "\"need_user_confirm\":true"
+ "}";
StringEntity entity = new StringEntity(reqdata,"utf-8");
entity.setContentType("application/json");
httpPost.setEntity(entity);
httpPost.setHeader("Accept", "application/json");
//完成签名并执行请求
CloseableHttpResponse response = httpClient.execute(httpPost);
try {
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == 200) { //处理成功
System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
} else if (statusCode == 204) { //处理成功,无返回Body
System.out.println("success");
} else {
System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));
throw new IOException("request failed");
}
} finally {
response.close();
}
}
重要参数说明:
• 入参“need_user_confirm”,取值请选择 “true”;
• 入参“risk_fund:name”,取值请选择【先免模式】中的枚举值。
更多参数、响应详情及错误码请参见创建支付分订单API接口文档
微信支付根据用户不同的使用场景(APP、小程序、微信内H5)分别提供了对应跳转确认订单页的方法,请根据场景进行选择,详见跳转确认订单页API文档
步骤说明:当用户确认订单时,微信会把相关信息异步回调的方式通知商户,商户需要接收处理,并按文档规范返回应答
注意:更多参数、响应详情及错误码请参见确认订单回调通知API接口文档
步骤说明:一般在创建订单后、订单完结成功后等关键流程中,商户可能有知晓订单状态的需求,此时即可通过该接口查询订单状态。
示例代码:public void GetServiceOrder() throws Exception{
//请求URL
HttpGet httpGet = new HttpGet("https://api.mch.weixin.qq.com/v3/payscore/serviceorder?service_id=500001&out_order_no=8416518464133&appid=wxd678efh567hg6787");
httpGet.setHeader("Accept", "application/json");
//完成签名并执行请求
CloseableHttpResponse response = httpClient.execute(httpGet);
try {
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == 200) { //处理成功
System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
} else if (statusCode == 204) { //处理成功,无返回Body
System.out.println("success");
} else {
System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));
throw new IOException("request failed");
}
} finally {
response.close();
}
}
步骤说明:订单为以下状态时可以取消订单:CREATED(已创单)、DOING(进行中)(包括商户完结支付分订单后,且支付分订单收款状态为待支付USER_PAYING)。
示例代码:
public void CancelServiceOrder() throws Exception{
//请求URL
HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/payscore/serviceorder/{out_order_no}/cancel");
// 请求body参数
String reqdata = "{"
+ "\"appid\":\"wxd678efh567hg6787\","
+ "\"service_id\":\"500001\","
+ "\"reason\":\"用户投诉\""
+ "}";
StringEntity entity = new StringEntity(reqdata,"utf-8");
entity.setContentType("application/json");
httpPost.setEntity(entity);
httpPost.setHeader("Accept", "application/json");
//完成签名并执行请求
CloseableHttpResponse response = httpClient.execute(httpPost);
try {
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == 200) { //处理成功
System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
} else if (statusCode == 204) { //处理成功,无返回Body
System.out.println("success");
} else {
System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));
throw new IOException("request failed");
}
} finally {
response.close();
}
}
更多参数、响应详情及错误码请参见 取消支付分订单API接口文档
步骤说明:用户服务结束后,商户通过请求完结支付分订单接口,通过微信支付分进行用户扣款操作。
注意:
public void CompleteServiceOrder() throws Exception{
//请求URL
HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/payscore/serviceorder/{out_order_no}/complete");
// 请求body参数
String reqdata = "{"
+ "\"appid\":\"wxd678efh567hg6787\","
+ "\"service_id\":\"500001\","
+ "\"post_payments\": ["
+ "{"
+ "\"name\":\"就餐费用服务费\","
+ "\"amount\":4000,"
+ "\"description\":\"就餐人均100元服务费:100/小时\","
+ "\"count\":1"
+ "}"
+ "],"
+ "\"post_discounts\": ["
+ "{"
+ "\"name\":\"满20减1元\","
+ "\"description\":\"不与其他优惠叠加\","
+ "\"amount\":4000"
+ "}"
+ "],"
+ "\"total_amount\":3900,"
+ "\"time_range\": {"
+ "\"start_time\":\"20091225091010\","
+ "\"end_time\":\"20091225121010\""
+ "},"
+ "\"location\": {"
+ "\"end_location\":\"嗨客时尚主题展餐厅\""
+ "},"
+ "\"profit_sharing\":false"
+ "}";
StringEntity entity = new StringEntity(reqdata,"utf-8");
entity.setContentType("application/json");
httpPost.setEntity(entity);
httpPost.setHeader("Accept", "application/json");
//完成签名并执行请求
CloseableHttpResponse response = httpClient.execute(httpPost);
try {
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == 200) { //处理成功
System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
} else if (statusCode == 204) { //处理成功,无返回Body
System.out.println("success");
} else {
System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));
throw new IOException("request failed");
}
} finally {
response.close();
}
}
更多参数、响应详情及错误码请参见完结支付分订单API接口文档
步骤说明:在用户扣款成功前、完结订单后(即订单状态为“待支付”),如需修改订单支付金额,可通过此接口进行订单金额修改。修改成功后,微信支付将按照修改后的金额进行用户扣款。
示例代码:
public void ModifyServiceOrder() throws Exception{
//请求URL
HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/payscore/serviceorder/{out_order_no}/modify");
// 请求body参数
String reqdata = "{"
+ "\"appid\":\"wxd678efh567hg6787\","
+ "\"service_id\":\"500001\","
+ "\"post_payments\": ["
+ "{"
+ "\"name\":\"就餐费用服务费\","
+ "\"amount\":4000,"
+ "\"description\":\"就餐人均100元服务费:100/小时\","
+ "\"count\":1"
+ "}"
+ "],"
+ "\"post_discounts\": ["
+ "{"
+ "\"name\":\"满20减1元\","
+ "\"description\":\"不与其他优惠叠加\","
+ "\"amount\":100"
+ "}"
+ "],"
+ "\"total_amount\":2000,"
+ "\"reason\":\"用户投诉\""
+ "}";
StringEntity entity = new StringEntity(reqdata,"utf-8");
entity.setContentType("application/json");
httpPost.setEntity(entity);
httpPost.setHeader("Accept", "application/json");
//完成签名并执行请求
CloseableHttpResponse response = httpClient.execute(httpPost);
try {
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == 200) { //处理成功
System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
} else if (statusCode == 204) { //处理成功,无返回Body
System.out.println("success");
} else {
System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));
throw new IOException("request failed");
}
} finally {
response.close();
}
}
更多参数、响应详情及错误码请参见修改订单金额API接口文档
步骤说明:由于一些原因,用户与商户达成线下支付或者其他支付方式支付的协议,商户可通过此接口告知微信支付该笔订单无需继续扣款,微信支付在接到此信息后将不再发起用户扣款。
示例代码:
public void SyncServiceOrder() throws Exception{
//请求URL
HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/payscore/serviceorder/{out_order_no}/sync");
// 请求body参数
String reqdata = "{"
+ "\"appid\":\"wxd678efh567hg6787\","
+ "\"service_id\":\"500001\","
+ "\"type\":\"Order_Paid\","
+ "\"detail\": {"
+ "\"paid_time\":\"20091225091210\""
+ "}"
+ "}";
StringEntity entity = new StringEntity(reqdata,"utf-8");
entity.setContentType("application/json");
httpPost.setEntity(entity);
httpPost.setHeader("Accept", "application/json");
//完成签名并执行请求
CloseableHttpResponse response = httpClient.execute(httpPost);
try {
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == 200) { //处理成功
System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
} else if (statusCode == 204) { //处理成功,无返回Body
System.out.println("success");
} else {
System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));
throw new IOException("request failed");
}
} finally {
response.close();
}
}
更多参数、响应详情及错误码请参见 同步服务订单信息API接口文档
步骤说明:微信支付按天提供交易账单文件,商户可以通过该接口获取账单文件的下载地址
示例代码:
public void TradeBill() throws Exception {
//请求URL
URIBuilder uriBuilder = new URIBuilder("https://api.mch.weixin.qq.com/v3/bill/tradebill");
uriBuilder.setParameter("bill_date", "2020-11-09");
uriBuilder.setParameter("bill_type", "ALL");
//完成签名并执行请求
HttpGet httpGet = new HttpGet(uriBuilder.build());
httpGet.addHeader("Accept", "application/json");
CloseableHttpResponse response = httpClient.execute(httpGet);
try {
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == 200) {
System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
} else if (statusCode == 204) {
System.out.println("success");
} else {
System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));
throw new IOException("request failed");
}
} finally {
response.close();
}
}
更多参数、响应详情及错误码请参见 申请交易账单API接口文档
步骤说明:通过申请交易账单接口获取到账单下载地址(download_url)后,再通过该接口获取到对应的账单文件,文件内包含交易相关的金额、时间、营销等信息,供商户核对订单、退款、银行到账等情况
示例代码:
public void DownloadUrl(String download_url) throws Exception{
PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(new ByteArrayInputStream(privateKey.getBytes("utf-8")));
//初始化httpClient
//该接口无需进行签名验证、通过withValidator((response) -> true)实现
httpClient = WechatPayHttpClientBuilder.create().withMerchant(mchId, mchSerialNo, merchantPrivateKey).withValidator((response) -> true).build();
//请求URL
//账单文件的下载地址的有效时间为30s
URIBuilder uriBuilder = new URIBuilder(download_url);
HttpGet httpGet = new HttpGet(uriBuilder.build());
httpGet.addHeader("Accept", "application/json");
//执行请求
CloseableHttpResponse response = httpClient.execute(httpGet);
try {
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == 200) {
System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
} else if (statusCode == 204) {
System.out.println("success");
} else {
System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));
throw new IOException("request failed");
}
} finally {
response.close();
}
}
注意:
更多参数、响应详情及错误码请参见 下载账单API接口文档
步骤说明:当用户完成支付,微信会把相关支付结果将通过异步回调的方式通知商户,商户需要接收处理,并按文档规范返回应答。
注意:
更多参数、响应详情及错误码请参见 支付成功回调通知API接口文档
微信支付根据用户不同的使用场景(APP、小程序、微信内H5)分别提供了对应跳转订单详情页的方法,请根据场景进行选择,详见跳转订单详情页API文档
A:同一个用户可以确认免押订单进行中的笔数是3笔(未完结&未支付的订单笔数,产品策略,可能会调整);如果用户进行中的订单超过3笔,则需要进行押金支付,如果有任何1笔待支付的订单,都是需要去支付押金的。
A:检查测试微信是否开通白名单,提供服务id和微信号联系运营开通白名单
A:① 检查商户号和appid是否配置了通用化接口权限,可以联系微信侧运营确认和配置通用化接口权限
② 如果商户开通的是免确认订单权限,创建订单时need_user_confirm只能传false,如果商户开通的是含确认订单权限,创建订单时need_user_confirm只能传true
A:检查商户号开通的是哪种模式的权限,需确认模式只能使用先免模式,免确认模式只能使用先享模式模式
A:请商户自行检查mch_id和appid是否有对应的绑定关系。绑定步骤参考“商家商户号与AppID账号关联管理”。