1.1 payParams参数列表
参数 | 类型 | 必填 | 描述 |
---|---|---|---|
customerId | Int | 是 | 支付平台分配给开发者的业务id,跟小程序产品要 |
serviceType | Int | 是 | 请用固定值:0 |
orderId | string(30) | 是 | 业务方订单号 |
orderCreateTime | Long | 是 | 业务订单创建时间,毫秒级时间戳 |
orderExpire | Int(11) | 否 | 交易失效时长,秒为单位 默认3600秒 |
payAmount | Int | 是 | 业务方订单实际需支付金额,单位为分 |
originalAmount | Int | 是 | 业务方订单原始需支付金额,用于展示优惠幅度用,单位为分,可以和payAmount一样 |
deviceType | Int | 是 | 请用固定值:3 |
notifyUrl | string(350) | 是 | 业务方接收支付结果的接口地址 接口规则见下方(1.1.1) |
productId | string(64) | 是 | 商品id |
showTitle | string(128) | 是 | 显示在第三方渠道的支付订单显示标题,建议使用小程序名称 |
showContent | string(128) | 否 | 显示在第三方渠道的支付订单显示内容 |
createUa | string(255) | 是 | 获取当前设备的UserAgent,可从http请求header中获取 |
extData | string(255) | 否 | 交易扩展信息,业务方扩展json串,支付通知时原样返回 分账相关请用固定值:{"profitSharing":"wechatPs","psExt":"{"optType":"wechatps_out_auto"}"} |
traceId | string(32) | 是 | 请求标识id,一个唯一的随机串即可 |
timestamp | Long | 是 | 请求时间戳 毫秒级 |
showQuote | string(255) | 否 | 收银台顶部文案,存在此文案则客户端使用该字段展示,否则使用原默认逻辑 |
version | string(20) | 是 | 请用固定值:1.0 |
signType | string(10) | 是 | 签名校验类型,目前仅支持MD5 |
sign | string(32) | 是 | 签名检验,生成规则见下方(1.1.2) |
defaultChoose | string(15) | 否 | 业务方可以指定默认的支付渠道,比如传bp,默认选择B币支付、alipay(支付宝)、wechat(微信) ,paypal(paypal)、ali_bank(网银支付)、bp(B币支付) |
extParams | string | 否 | 请用固定值:{"profitSharing":"wechatPs","psExt":"{"optType":"wechatps_out_auto"}"} |
1.1.1 payParams中的notifyUrl接口规则
例:业务 notifyUrl 传入 https://xxx.com/abc , 回调请求地址为 https://xxx.com/abc?msgId=123&msgContent=通知JSON字符消息体
notifyUrl 可以自己补充参数, 如 https://xxx.com/abc?axv=1 ,回调会自适应请求地址 https://xxx.com/abc?axv=1&msgId=123&msgContent=支付中心返回的JSON串
注意事项:
- notifyUrl通知方式为
GET
请求 - 支付中心调用接入方接口会回传两个参数
msgId
和msgContent
msgContent
存储的JSON字段,未来有可能会新增新的一级字段,且参与签名,验签或解析时应当考虑兼容新增字段。- 接入方需要校验 sign 以确保回调信息是来自支付中心的合法回调。签名校验方式如发起支付时的签名方式。
- 重试策略为 1, 10, 20, 60, 60, 180, 360, 600, 600, 3600, 7200, 7200, 代表回调未得到业务方成功响应后延迟重试时间(秒)
Java解析示例
JSONObject jsonObject = JSONObject.parseObject(msgContent);
Map<string,string> map = new HashMap<>();
for(string key : jsonObject.keySet()){
map.put(key, jsonObject.get(key).toString());
}
支付中心返回的支付结果msgContent JSON串参数说明如下
参数 | 描述 | 类型 | 是否一定返回 |
---|---|---|---|
customerId | 支付平台分配给开发者的业务id | int(11) | 是 |
serviceType | 业务方业务类型 | int(6) | 否 |
txId | 支付平台支付id | string(32) | 是 |
orderId | 业务方订单号 | string | 是 |
deviceType | 支付设备渠道类型:传3 | Int | 是 |
payStatus | 支付状态,FINISHED(交易成功)、SUCCESS(成功)、REFUND(退款中)、PAYING(支付中)、CLOSED(关闭)、NOT_PAY(未支付)、FAIL(支付失败)、WITHDRAW(支付撤销) 支付回调暂时仅通知 SUCCESS, 其他状态不通知。 | string(15) | 是 |
payChannelId | 支付渠道id, 用户实际选择的支付实体渠道。(payChannel 代表笼统的微信、支付宝等第三方渠道, payChannelId 代表实际签约的实体渠道 id) | string(11) | 是 |
payChannel | 支付渠道:alipay(支付宝)、wechat(微信) ,paypal(paypal), iap(In App Purchase)、qpay(QQ支付)、huabei(花呗支付)、ali_bank(网银支付)、bocom(交行信用卡支付)、bp(B币支付) | string(15) | 是 |
payChannelName | 支付渠道名称 如支付宝、微信、PayPal、IAP、QQ、花呗、网银支付、B币支付 | string(30) | 是 |
payAccount | 支付渠道账号 | string(50) | 否 |
payBank | 支付银行 | string(15) | 否 |
feeType | 货币类型,默认人民币:CNY, 美元:USD, 日币:JPY, 港币:HKD | string(10) | 否 |
payAmount | 业务方订单实际需支付金额,单位为分 | Int | 是 |
payMsgContent | 支付返回的额外信息,json格式字符串,比如:payCounponAmount:使用B币券金额(单位 分),payBpAmount:B币金额(分),productId:商品id | string(255) | 是 |
extData | 交易扩展信息,业务方扩展json串,支付通知时原样返回 | string(255) | 否 |
orderPayTime | 订单支付时间,格式:0000-00-00 00:00:00 | string(20) | 否 |
timestamp | 请求时间戳 毫秒级 | Long | 是 |
traceId | 请求标识id | string(32) | 是 |
signType | 签名校验类型,默认MD5 | string(10) | 是 |
sign | 签名(应当支持支付平台这边新增返回字段) | string(32) | 是 |
支付结果msgContent示例
{
"customerId": 1,
"serviceType": 0,
"txId": 30271458087***,
"orderId": "928123***",
"feeType": "CNY",
"payStatus": "SUCCESS",
"payChannel": "bp",
"payChannelName": "B币",
"payChannelId": 99,
"payAmount": 9,
"payMsgContent": "{\"payCounponAmount\":0,\"payBpAmount\":9}",
"payAccountId": "27515323",
"deviceType": 2,
"orderPayTime": "2018-09-07 17:39:37",
"timestamp": "1536313177258",
"traceId": "3027145809363013632",
"extData": "{}",
"signType": "MD5",
"sign": "5e32095c9a3f49a8001a90a5c162461b",
"expiredTime": 0
}
接入方的notifyUrl接口需返回是否处理完成,给支付中心返回一个字符串,值如下
- SUCCESS 表示成功
- FAIL 表示失败 支付平台会立即重试
- REPUBLISH 支付平台稍后重试
支付中心明确收到指定返回后,才认为通知成功,否则会重试,业务方需保证该回调接口的幂等性,注意返回值是大写字符串。
1.1.2 payParams中sign签名生成规则如下
- 将payParams中参数按照字典排列后连接token(token由支付中心未接入方分配)如:k1=v1&k2=v2&……&token=xxx
- 进行md5加密后全部小写 sign生成如下:
sign = md5(k1=v1&k2=v2&……&token=xxx).toLowerCase()
【生成签名示例 Java 代码】
public class RestSignUtils {
/**
* 对实体类进行签名
* @param o
* @param token
*/
public static string sign(Object o, string token) {
BaseVO baseVO = new BaseVO();
JsonElement jsonElement = new JsonParser().parse(o);
try {
Map<string, string> paramMap = new HashMap<>();
JsonObject jsonObject = jsonElement.getAsJsonObject();
Iterator<Map.Entry<string, JsonElement>> iterator = jsonObject.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<string, JsonElement> entry = iterator.next();
if (entry.getValue().isJsonPrimitive()) {
paramMap.put(entry.getKey(), entry.getValue().getAsString());
} else {
paramMap.put(entry.getKey(), entry.getValue().toString());
}
}
return getSign(paramMap, token);
} catch (Exception e) {
BiliLog.error("sign failed. error [{}]", e.getMessage());
throw new RuntimeException("签名计算错误");
}
}
public static string getSign(Map<string, string> paramterMap, string payToken) {
List<Map.Entry<string, string>> paramsList = new ArrayList<>(paramterMap.entrySet());
try {
Collections.sort(paramsList, new Comparator<Map.Entry<string, string>>() {
@Override
public int compare(Map.Entry<string, string> o1, Map.Entry<string, string> o2) {
return o1.getKey().compareTo(o2.getKey());
}
});
List<string> params = new ArrayList<>();
for (Map.Entry<string, string> singleOne: paramsList) {
params.add(string.format("%s=%s", singleOne.getKey(), singleOne.getValue()));
}
params.add("token=" + payToken);
string orignalSign = StringUtils.join(params, "&");
return Md5Utils.GetMD5Code(orignalSign).toLowerCase();
} catch (Exception e) {
BiliLog.warn("parameter sort failed. {}", e.getMessage());
}
return null;
}
}