跳转接入
# 快速开始
推荐使用内嵌接入
由 pingpong checkout 提供收银台⻚面,商户无需自行开发收银台⻚面,执行完结账请求,直接跳转至 pingpong checkout 收银台⻚面。
# 收银台模式系统交互流程

# 如何接入
调用收银台 v2/checkout 接口
v2/checkout 接口返回paymentUrl
商户将用户⻚面重定向至 paymentUrl
用户浏览器渲染PingPongPay 收银台⻚面,完成支付
# 请求下单支付
# 请求地址
https://{host}/v2/checkout
# 请求参数
参数必填属性说明:必填(M),可选(O),条件必填(C)。
# 请求参数签名
# 加签参数列表
参数名 | 描述 |
---|---|
clientId | PingPong商户号 |
accId | PingPong商户店铺号 |
amount | 交易金额 |
currency | 交易币种 |
cardNum | 交易卡号 |
transactionId | PingPong交易流水号 |
merchantTransactionId | 商户交易流水号 |
signType | 加签类型 |
shopperResultUrl | 商户自定义接收重定向的结果 URL |
# 获取签名参数列表
准备一个ArrayList 加签参数列表
遍历收到的请求参数列表。
每次循环都比较请求参数的参数名是否在加签参数列表
在加签参数列表的参数加入新的签名参数列表
# PHP伪代码示例:
<?php
$request = isPingPongPay($requestParams);
if(empty($request)){
throw new Error("验签失败");
}
$needSign = [];
$scope = [
"clientId",
"accId",
"amount",
"currency",
"cardNum",
"transactionId",
"merchantTransactionId",
"requestId",
"signType",
]
foreach($request as $key=>$value){
if(in_array($key,$scope)){
$needSign[$key] = $value;
}
// then if not empty $needSign you will to Generate signature string
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 签名串的生成
待签名参数列表按照字典序排序
将排序后的待签名参数列表转成url查询字符串(用'=' 进行参数名和参数值(trim 后的值)的拼接,用'&'进行多 个参数之间的拼接,即 key1=val1&key2=val2&key3=val。)
3.拼接签名密钥(secret): 签名密钥放入签名串的位置为签名串的开头,即{salt}key1=val2&key2=val2&key3=val3
- 签名串进行MD5运算后所有字符串转成大写,即可获得正确的签名
# 请求示例
POST /v2/checkout HTTP/1.1
Host: {host}
Content-Type: application/json
Content-Length: 3012
{
"sign": "3F9DF2F986EFCE55919C2CA991689D4C",
"signType": "MD5",
"accId": "2018092714313010016291",
"amount": "20",
"currency": "USD",
"merchantTransactionId": "MTN193495030728",
"paymentType": "SALE",
"shopperResultUrl": "http://127.0.0.1:8010/demo/checkoutResult",
"threeDSecure": "N",
"riskInfo": {
"device": {
"orderTerminal": "01",
"fingerprintId": "e10adc3949ba59abbe56e057f20f883e"
},
"customer": {
"customerId": "UN00000001",
"firstName": "James",
"lastName": "LeBron",
"email": "demo@pingpongx.com",
"domain": "pingpongx.com",
"phone": "15988890852",
"mobile": "15988890856",
"workPhone": "15988890852",
"identificationType": "ID",
"identificationId": "330102199003070115",
"registerTime": "20191101122000",
"registerIp": "222.126.52.23",
"registerTerminal": "PC",
"registerCountry": "US",
"registerRange": "1",
"orderTime": "20191201122000",
"orderIp": "222.126.52.23",
"orderCountry": "US",
"payIp": "222.126.52.23",
"payCountry": "US",
"loginTime": "20200427122000",
"loginIp": "222.126.52.23",
"lastPayTime": "20200427122000",
"acquisitionChannel": "Seach engine",
"firstOrder": "N",
"nonMemberOrder": "N",
"preferentialOrder": "N",
"birthDate": "20000212",
"customerStatus": "EXISTING"
},
"goods": [
{
"name": "Macaron",
"description": "Colorful macaron",
"sku": "20191201331",
"averageUnitPrice": "20",
"number": "1",
"virtualProduct": "N"
}
],
"shipping": {
"firstName": "James",
"lastName": "LeBron",
"phone": "13588185079",
"email": "demo@pingpognx.com",
"street": "1986 Broad Street",
"postcode": "35222",
"city": "Birmingham",
"state": "Alabama",
"country": "US",
"lastModifierStreetTime": "20191225162010",
"lastModifierPhoneTime": "20191225162010"
},
"billing": {
"firstName": "James",
"lastName": "LeBron",
"phone": "13588185079",
"email": "demo@pingpognx.com",
"street": "1986 Broad Street",
"postcode": "35222",
"city": "Birmingham",
"state": "Alabama",
"country": "US"
},
"ecommerce": {
"freeShipping": "N",
"shippingMethod": "sea"
}
},
"notificationUrl": "http://127.0.0.1:8010/demo/callback/checkoutCallback",
"merchantUserId": "UN00000001",
"remark": "demo-checkout-normal"
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
<?php
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => 'https://%7Bhost%7D/v2/checkout',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS =>'{
"sign": "3F9DF2F986EFCE55919C2CA991689D4C",
"signType": "MD5",
"accId": "2018092714313010016291",
"amount": "20",
"currency": "USD",
"merchantTransactionId": "MTN193495030728",
"paymentType": "SALE",
"shopperResultUrl": "http://127.0.0.1:8010/demo/checkoutResult",
"threeDSecure": "N",
"riskInfo": {
"device": {
"orderTerminal": "01",
"fingerprintId": "e10adc3949ba59abbe56e057f20f883e"
},
"customer": {
"customerId": "UN00000001",
"firstName": "James",
"lastName": "LeBron",
"email": "demo@pingpongx.com",
"domain": "pingpongx.com",
"phone": "15988890852",
"mobile": "15988890856",
"workPhone": "15988890852",
"identificationType": "ID",
"identificationId": "330102199003070115",
"registerTime": "20191101122000",
"registerIp": "222.126.52.23",
"registerTerminal": "PC",
"registerCountry": "US",
"registerRange": "1",
"orderTime": "20191201122000",
"orderIp": "222.126.52.23",
"orderCountry": "US",
"payIp": "222.126.52.23",
"payCountry": "US",
"loginTime": "20200427122000",
"loginIp": "222.126.52.23",
"lastPayTime": "20200427122000",
"acquisitionChannel": "Seach engine",
"firstOrder": "N",
"nonMemberOrder": "N",
"preferentialOrder": "N",
"birthDate": "20000212",
"customerStatus": "EXISTING"
},
"goods": [
{
"name": "Macaron",
"description": "Colorful macaron",
"sku": "20191201331",
"averageUnitPrice": "20",
"number": "1",
"virtualProduct": "N"
}
],
"shipping": {
"firstName": "James",
"lastName": "LeBron",
"phone": "13588185079",
"email": "demo@pingpognx.com",
"street": "1986 Broad Street",
"postcode": "35222",
"city": "Birmingham",
"state": "Alabama",
"country": "US",
"lastModifierStreetTime": "20191225162010",
"lastModifierPhoneTime": "20191225162010"
},
"billing": {
"firstName": "James",
"lastName": "LeBron",
"phone": "13588185079",
"email": "demo@pingpognx.com",
"street": "1986 Broad Street",
"postcode": "35222",
"city": "Birmingham",
"state": "Alabama",
"country": "US"
},
"ecommerce": {
"freeShipping": "N",
"shippingMethod": "sea"
}
},
"notificationUrl": "http://127.0.0.1:8010/demo/callback/checkoutCallback",
"merchantUserId": "UN00000001",
"remark": "demo-checkout-normal"
}',
CURLOPT_HTTPHEADER => array(
'Content-Type: application/json'
),
));
$response = curl_exec($curl);
curl_close($curl);
echo $response;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
OkHttpClient client = new OkHttpClient().newBuilder()
.build();
MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, "{\n \"sign\": \"3F9DF2F986EFCE55919C2CA991689D4C\",\n \"signType\": \"MD5\",\n \"accId\": \"2018092714313010016291\",\n \"amount\": \"20\",\n \"currency\": \"USD\",\n \"merchantTransactionId\": \"MTN193495030728\",\n \"paymentType\": \"SALE\",\n \"shopperResultUrl\": \"http://127.0.0.1:8010/demo/checkoutResult\",\n \"threeDSecure\": \"N\",\n \"riskInfo\": {\n \"device\": {\n \"orderTerminal\": \"01\",\n \"fingerprintId\": \"e10adc3949ba59abbe56e057f20f883e\"\n },\n \"customer\": {\n \"customerId\": \"UN00000001\",\n \"firstName\": \"James\",\n \"lastName\": \"LeBron\",\n \"email\": \"demo@pingpongx.com\",\n \"domain\": \"pingpongx.com\",\n \"phone\": \"15988890852\",\n \"mobile\": \"15988890856\",\n \"workPhone\": \"15988890852\",\n \"identificationType\": \"ID\",\n \"identificationId\": \"330102199003070115\",\n \"registerTime\": \"20191101122000\",\n \"registerIp\": \"222.126.52.23\",\n \"registerTerminal\": \"PC\",\n \"registerCountry\": \"US\",\n \"registerRange\": \"1\",\n \"orderTime\": \"20191201122000\",\n \"orderIp\": \"222.126.52.23\",\n \"orderCountry\": \"US\",\n \"payIp\": \"222.126.52.23\",\n \"payCountry\": \"US\",\n \"loginTime\": \"20200427122000\",\n \"loginIp\": \"222.126.52.23\",\n \"lastPayTime\": \"20200427122000\",\n \"acquisitionChannel\": \"Seach engine\",\n \"firstOrder\": \"N\",\n \"nonMemberOrder\": \"N\",\n \"preferentialOrder\": \"N\",\n \"birthDate\": \"20000212\",\n \"customerStatus\": \"EXISTING\"\n },\n \"goods\": [\n {\n \"name\": \"Macaron\",\n \"description\": \"Colorful macaron\",\n \"sku\": \"20191201331\",\n \"averageUnitPrice\": \"20\",\n \"number\": \"1\",\n \"virtualProduct\": \"N\"\n }\n ],\n \"shipping\": {\n \"firstName\": \"James\",\n \"lastName\": \"LeBron\",\n \"phone\": \"13588185079\",\n \"email\": \"demo@pingpognx.com\",\n \"street\": \"1986 Broad Street\",\n \"postcode\": \"35222\",\n \"city\": \"Birmingham\",\n \"state\": \"Alabama\",\n \"country\": \"US\",\n \"lastModifierStreetTime\": \"20191225162010\",\n \"lastModifierPhoneTime\": \"20191225162010\"\n },\n \"billing\": {\n \"firstName\": \"James\",\n \"lastName\": \"LeBron\",\n \"phone\": \"13588185079\",\n \"email\": \"demo@pingpognx.com\",\n \"street\": \"1986 Broad Street\",\n \"postcode\": \"35222\",\n \"city\": \"Birmingham\",\n \"state\": \"Alabama\",\n \"country\": \"US\"\n },\n \"ecommerce\": {\n \"freeShipping\": \"N\",\n \"shippingMethod\": \"sea\"\n }\n },\n \"notificationUrl\": \"http://127.0.0.1:8010/demo/callback/checkoutCallback\",\n \"merchantUserId\": \"UN00000001\",\n \"remark\": \"demo-checkout-normal\"\n}");
Request request = new Request.Builder()
.url("https://{host}/v2/checkout")
.method("POST", body)
.addHeader("Content-Type", "application/json")
.build();
Response response = client.newCall(request).execute();
2
3
4
5
6
7
8
9
10
// Make sure to add code blocks to your code group
# 签名串示例
signContent:accId=2018092714313010016291&amount=20¤cy=USD&merchantTransactionId=MTN193495030728¬ificationUrl=http://127.0.0.1:8010/demo/callback/checkoutCallback&shopperResultUrl=http://127.0.0.1:8010/demo/checkoutResult&signType=MD5
# 重要入参说明
1. merchantTransactionId 应是全局唯一,不可重复
2. amount 精确到两位小数,没有小数部分的补零。(如 25.12 或 20.00)
3. paymentType 一般为SALE 如果要对接AUTH请在对接过程告知,并在测试报告中声明,一定通过验收后才能上线,以免发生交易问题
4. 在收银台模式下 device browserInfo 可以自动抓取,可以不传
5. shipping billing goods 不能为空 eCommerce airline reCharge carRental 根据行业情况填写,这些参数影响交易成功率,请详实填写。
6. shipping billing state 美国加拿大地区必须填写二字简码,有些地区没有state,可以填写空字符串。
7. merchantUserId 必须全局唯一 没登录或者获取不到的情况请传空字符串。
# 响应参数
参数字段 | 参数属性 | 参数说明 |
---|---|---|
clientId | M | PingPong 商户商户号 |
accId | M | PingPong 商户店铺编号 |
merchantTransactionId | M | 商户网站的的交易流水号 |
code | M | 结果状态码 |
description | M | 结果描述 |
token | M | 收银台模式下,本次结账请求的唯一标示 |
paymentUrl | M | PingPong 支付收银台地址 |
innerJsUrl | M | PingPong 内嵌 JS 文件内容地址 |
signType | M | 签名规约,支持 MD5、SHA256,具体⻅本文“签名规约” 一栏 |
sign | M | 签名内容,具体⻅本文“签名规约”一栏 |
remark | O | 商户扩展字段 |
paymentHtml | O | 预留字段 |
# 响应示例
{
"accId": "2018092714313010016291",
"clientId": "2018092714313010016",
"code": "001000",
"description": "Successful request",
"innerJsUrl": "https://pay-cdn.pingpongx.com/production/static/sdk/ppPay.min.js?token=vr_YVR8u7rn7C1gG97DOg5W0OxzazxNYIE56ShWjA4lJrY4wchTnb47oNmp-9ubP",
"merchantTransactionId": "MTN193495030728",
"paymentUrl": "https://sandbox-pay-checkout.pingpongx.com/index.html?token=vr_YVR8u7rn7C1gG97DOg5W0OxzazxNYIE56ShWjA4lJrY4wchTnb47oNmp-9ubP",
"sign": "06D1C606847FD77CC70AAEB94A2A40D6",
"signType": "MD5",
"token": "vr_YVR8u7rn7C1gG97DOg5W0OxzazxNYIE56ShWjA4lJrY4wchTnb47oNmp-9ubP"
}
2
3
4
5
6
7
8
9
10
11
12
# 响应加签串示例
signContent:accId=2018092714313010016291&clientId=2018092714313010016&code=001000&description=Successful request&innerJsUrl=https://pay-cdn.pingpongx.com/production/static/sdk/ppPay.min.js?token=vr_YVR8u7rn7C1gG97DOg5W0OxzazxNYIE56ShWjA4lJrY4wchTnb47oNmp-9ubP&merchantTransactionId=MTN193495030728&paymentUrl=https://sandbox-pay-checkout.pingpongx.com/index.html?token=vr_YVR8u7rn7C1gG97DOg5W0OxzazxNYIE56ShWjA4lJrY4wchTnb47oNmp-9ubP&signType=MD5&token=vr_YVR8u7rn7C1gG97DOg5W0OxzazxNYIE56ShWjA4lJrY4wchTnb47oNmp-9ubP
# 重要出参说明
根据是否能够取到token或者paymentUrl来判断是否成功
响应字段paymentUrl为跳转收银台地址
# 3DS
收银台模式下,3DS 流程由 pingpong checkout 进行了内部封装,无需商户额外接入。
# 预授权
# 什么是预授权
- 商户在持卡人消费前先冻结持卡人creditcard的余额或者额度。
- 持卡人消费结束后,商户再正式扣掉这部分资金,常用于酒店住宿、出租等行业。
- 线上交易正常预授权资金冻结期限为7天,部分发卡行是30天。
- PingPongPay默认不会自动解冻持卡人资金。
- 预授权交易7天或者30天后,如果商户在这期间没有任何操作,发卡行会自动解冻持卡人冻结的资金。
- 商户发起Auth之后必须发起在恰当时间(通常为7天)发起CAPTURE,否则交易将被超时取消
# 如何发起预授权交易
v2/checkout 接口中
交易类型:
- SALE-直接付款
- AUTH-预授权
填入paymentType= AUTH 即视为AUTH 业务
# CAPTURE
# 什么是CAPTURE
对已经预授权成功的交易,在资金冻结期限内使用预授权完成进行请款操作。
# 业务前提
针对“预授权”交易可以发起“预授权完成”操作。
# 业务限制
- 当前“预授权”交易未被判定为“预授权取消”。
- 预授权完成的金额需小于等于关联的 CAPTURE 交易。
# 如何发起
收银台模式和端到端模式都请求二次交易接口,填入paymentType=CAPTURE发起退款
# 接口地址
https://{host}/v2/payment/{transactionId}
参数详见 退款预授权
# VOID
# 什么是VOID
对已经预授权的交易,通知发卡行进行预授权撤销,预授权撤销成功后发卡行会解冻持卡人冻结的资金。
# 业务前提
针对“预授权”交易可以发起“预授权撤销”操作。
# 业务限制
- 当前“预授权”交易未被判定为“预授权完成”。
- 预授权撤销只能全额撤销。
# 如何发起
收银台模式和端到端模式都请求二次交易接口,填入paymentType=VOID发起退款
# 接口地址
https://{host}/v2/payment/{transactionId}
参数详见退款预授权