通知
注意事项
- 通知地址可以通过两种方式给到我们,一种是由商户在
Onerway
注册时提供,另一种是通过交易接口中的notifyUrl
指定。 - 优先使用
notifyUrl
作为通知地址,如果没有传则会找后台配置的,如果还是找不到则不会发送通知。 - 支付结果以异步通知为准,同步响应中的
status
字段不能用来判断支付结果!
验签步骤
注意
- 异步通知未来可能新增参数,新增参数默认参与验签
- 请商户在验签时注意剔除签名列为
NO
的参数,不要按照现有的签名列为YES
的参数进行验签,以免未来因为新增字段导致验签失败
通知参数
名称 | 类型 | 长度 | 签名 | 描述 |
---|---|---|---|---|
notifyType | String | / | Yes | 通知类型。请参阅 |
txnType | String | / | Yes | 交易类型。请参阅 当 notifyType 为 TXN 时返回,用于区分支付和退款 |
transactionId | String | 20 | Yes | Onerway 创建的交易订单号,对应商户订单号 |
originTransactionId | String | 20 | No | 来源于 Onerway 的原始交易订单号。在退款等反向交易的通知中返回对应的正向交易的 Onerway 交易订单号 |
merchantTxnId | String | 64 | Yes | 商户创建的商户交易订单号,不同的订单号视为不同的交易 |
originMerchantTxnId | String | 64 | No | 商户原交易订单号,在退款等反向交易的通知中返回对应的正向交易的商户交易订单号 |
merchantNo | String | 20 | Yes | 商户号。 商户注册时,OnerWay 会为商户创建商户号 |
responseTime | String | / | Yes | 接口响应时间,格式为yyyy-MM-dd HH:mm:ss |
txnTime | String | / | Yes | 交易完成时间,格式为yyyy-MM-dd HH:mm:ss |
txnTimeZone | String | / | Yes | 交易完成时区,例如:+08:00 |
orderAmount | String | 19 | Yes | 交易订单金额 |
orderCurrency | String | 8 | Yes | 交易订单的货币。 请参阅 ISO 4217 货币代码 |
txnAmount | String | 19 | Yes | 订单金额转换成结算币种后的金额 |
txnCurrency | String | 8 | Yes | 结算币种。 请参阅 ISO 4217 货币代码 |
settleRate | String | 19 | Yes | 汇率(txnAmount = orderAmount * settleRate) |
customsDeclarationAmount | String | 19 | No | 可报关金额 |
customsDeclarationCurrency | String | 8 | No | 可用于报关的金额对应币种。请参阅 ISO 4217 货币代码 |
paymentMethod | String | 64 | No | 具体支付方式,包括卡 和本地支付 类型 |
walletTypeName | String | 128 | No | 钱包的品牌名称 |
status | String | 1 | Yes | 交易处理结果。 枚举如下:S - 交易成功/取消交易成功 F - 交易失败/审批不通过/取消交易失败 |
reason | String | 512 | Yes | 交易失败的原因 |
periodValue | String | / | No | 分期付款期数 |
contractId | String | 20 | Yes | 订阅合同id ,在订阅首购时会返回 |
tokenId | String | 300 | Yes | token id ,用于订阅复购和Token支付 |
cardTokenId | String | 300 | Yes | 绑卡token id ,仅特殊场景下返回 |
tokenExpireTime | String | / | No | token 过期时间,在协议代扣申请token 时会返回 |
eci | String | 2 | Yes | 责任转移 |
chargebackDate | String | / | Yes | 发生拒付的日期,格式为yyyy-MM-dd |
importTime | String | / | Yes | Onerway 接收拒付交易的时间,格式为yyyy-MM-dd HH:mm:ss |
appealDueTime | String | / | Yes | 申诉资料提交截止时间,格式为yyyy-MM-dd HH:mm:ss |
chargebackAmount | String | 19 | Yes | 拒付金额 |
chargebackCurrency | String | 8 | Yes | 拒付金额对应币种。 请参阅 ISO 4217 货币代码 |
chargebackStatus | String | 16 | Yes | 拒付状态。请参阅 |
chargebackArn | String | 128 | Yes | 拒付 ARN |
chargebackCode | String | 32 | Yes | 拒付代码 |
chargebackReason | String | 1024 | Yes | 拒付原因 |
cardBinCountry | String | 64 | Yes | 卡bin 国家。请参阅 ISO 3316。 |
expireDate | String | / | Yes | 过期日期,格式为yyyy-MM-dd 。 |
subscriptionStatus | String | 2048 | Yes | 订阅状态,请参阅 |
dataStatus | String | 2048 | Yes | 订阅合同状态,请参阅 |
products | String | 1024 | Yes | 商品信息 |
subscriptionChangeTime | String | / | Yes | 订阅实际更新日 |
metaData | String | 2048 | Yes | 补充字段,供商户自定义 |
scenarios | String | 2048 | Yes | 订阅场景:SUBSCRIPTION INITIAL - 订阅首购SUBSCRIPTION RENEWAL - 订阅复购SUBSCRIPTION CARD REPLACEMENT - 订阅换卡SUBSCRIPTION CHANGED - 订阅更新SUBSCRIPTION CANCELED - 订阅取消SUBSCRIPTION ENDED - 订阅到期 可结合 notifyType 使用,判断订阅交易场景 |
sign | String | / | No | 签名字符串,请参阅签名接口 |
不参与验签的字段
'originTransactionId', 'originMerchantTxnId', 'customsDeclarationAmount', 'customsDeclarationCurrency', 'paymentMethod', 'walletTypeName', 'periodValue', 'tokenExpireTime', 'sign'
剔除参数代码示例
php
/*
$params 需要加签的数据;
参数类型一维数组array;
$PrivateKey 商户秘钥;
参数类型字符串;
*/
function ASCII_HASH($params , $PrivateKey){
if(!empty($params)){
$p = ksort($params);
//需要剔除的参数
$badkey = array('originTransactionId','originMerchantTxnId','customsDeclarationAmount','customsDeclarationCurrency','paymentMethod','walletTypeName','periodValue','tokenExpireTime','sign');
if($p){
$strs = '';
foreach ($params as $k=>$val){
//剔除为"NO"的参数
if((!empty($val) || $val == 0) && $k != 'sign' && $k != 'route' && !in_array($k, $badkey))
{
$strs .= $val ;
}
}
$strs = $strs.$PrivateKey ;
return hash('sha256' , $strs);
}
}
return 'error';
}
1
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
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
java
/**
* 接收通知回调
*
* @param webhook TreeMap 接收异步通知
* @return transactionId
*/
@PostMapping("webhook")
public Object webhook(@RequestBody TreeMap<String, Object> webhook) {
// 保存原有签名
String originalSign = webhook.get("sign");
// 创建新的Map用于验签,避免修改原始数据
TreeMap<String, Object> verifyMap = new TreeMap<>(webhook);
// 仅在异步通知验签时剔除这些字段
List<String> notifyExcludeFields = Arrays.asList(
"originTransactionId", "originMerchantTxnId", "customsDeclarationAmount",
"customsDeclarationCurrency", "paymentMethod", "walletTypeName",
"periodValue", "tokenExpireTime", "sign"
);
// 仅针对异步通知验签时移除特定字段
for (String key : notifyExcludeFields) {
verifyMap.remove(key);
}
// todo: 调用原有签名方法进行字符串拼接并生成签名
String sign = hash(verifyMap);
// 验证签名是否正确
if (!sign.equals(originalSign)) {
log.error("Invalid signature. 生成的签名: {}; 请求里的签名: {}", sign, originalSign);
// todo: 验签失败,非Onerway异步通知/伪造通知,商户自定义处理逻辑
}
// 验签通过后,返回transactionId
return webhook.get("transactionId");
}
1
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
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
响应参数
商户需在接收到异步通知后,只需要响应 transactionId
的值,不要返回其他任何参数
名称 | 类型 | 签名 | 描述 |
---|---|---|---|
transactionId | String | No | Onerway 创建的交易订单号,对应商户订单号 |
响应示例
1798262509925699584 ✅
"1798262509925699584" ❌
json
// 错误示例1
{
"transactionId": "1798262509925699584"
}
// 错误示例2
{
"transactionId": "1798262509925699584",
"status": "S"
}
// 错误示例3
{
"respCode": "20000",
"respMsg": "Success",
"data": "1798262509925699584"
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
通知示例
json
{
"//": "支付通知",
"notifyType": "TXN",
"transactionId": "1599953668994019328",
"txnType": "SALE",
"merchantNo": "800096",
"merchantTxnId": "1670293654000",
"originMerchantTxnId": null,
"responseTime": "2022-12-06 10:27:39",
"txnTime": "2022-12-06 10:27:35",
"txnTimeZone": "+08:00",
"orderAmount": "29.00",
"orderCurrency": "USD",
"txnAmount": "29.00",
"txnCurrency": "USD",
"customsDeclarationAmount": null,
"customsDeclarationCurrency": null,
"status": "S",
"contractId": null,
"tokenId": null,
"tokenExpireTime": null,
"eci": null,
"reason": "{\"respCode\":\"20000\",\"respMsg\":\"Success\"}",
"periodValue": null,
"paymentMethod": "VISA",
"walletTypeName": null,
"sign": "..."
}
1
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
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
json
{
"notifyType": "TXN",
"transactionId": "1910535617541181440",
"txnType": "SALE",
"merchantNo": "800209",
"merchantTxnId": "efdcc32c-353e-45fa-a080-b646133bb18e",
"responseTime": "2025-04-11 11:29:38",
"txnTime": "2025-04-11 11:29:22",
"txnTimeZone": "+08:00",
"orderAmount": "0.00",
"orderCurrency": "USD",
"status": "S",
"contractId": "1910535617788645376",
"tokenId": "59dd45a1a8c9208a57ca4749def72915007434c9aa5b1a1e7665b533c7b77565",
"cardTokenId": "a7f92aa129d203d51a6b0d2be3d7a96741d62aca0295e9050c43c71d9c143e2a",
"cardBinCountry": "US",
"reason": "{\"respCode\":\"20000\",\"respMsg\":\"Success\"}",
"sign": "e7d72477473bea046031ce07c8068de058ebaeb0be633f186e2ef3a44fed7eb6",
"paymentMethod": "VISA",
"subscriptionManageUrl": "https://sandbox-myscribe.onerway.com/pages/subscription-list/details?contractId=eyJjb250cmFjdElkIjoxOTEwNTM1NjE3Nzg4NjQ1Mzc2LCJtZXJjaGFudE5vIjo4MDAyMDksIm1lcmNoYW50Q3VzdElkIjoiQ3VzdElkLTlUMTctUVhXUCIsIm5vdGlmaWNhdGlvbkVtYWlsIjpudWxsLCJhcHBJZCI6IjE3Mjc4ODA4NDYzNzg0MDE3OTIifQ==",
"subscriptionStatus": "trialing",
"dataStatus": "1",
"products": "[{\"currency\":\"USD\",\"name\":\"feijoa\",\"num\":\"86\",\"price\":\"620.59\",\"type\":\"nulla est\"},{\"currency\":\"USD\",\"name\":\"bush tomato\",\"num\":\"63\",\"price\":\"976.59\",\"type\":\"cillum eiusmod pariatur sed deserunt\"}]",
"channelRequestId": "8002091910535623119343617",
"scenarios": "SUBSCRIPTION_INITIAL"
}
1
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
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
json
{
"notifyType": "TXN",
"transactionId": "1910535892016435200",
"txnType": "SALE",
"merchantNo": "800209",
"merchantTxnId": "1910535890577788928",
"responseTime": "2025-04-11 11:30:29",
"txnTime": "2025-04-11 11:30:27",
"txnTimeZone": "+08:00",
"orderAmount": "1.00",
"orderCurrency": "USD",
"status": "S",
"contractId": "1910535617788645376",
"tokenId": "59dd45a1a8c9208a57ca4749def72915007434c9aa5b1a1e7665b533c7b77565",
"cardBinCountry": "US",
"reason": "{\"respCode\":\"20000\",\"respMsg\":\"Success\"}",
"sign": "a8e14411932559d35eec9e9e1ca97504b3abdf141feb13f682162b81d62f89a2",
"paymentMethod": "VISA",
"subscriptionManageUrl": "https://sandbox-myscribe.onerway.com/pages/subscription-list/details?contractId=eyJjb250cmFjdElkIjoxOTEwNTM1NjE3Nzg4NjQ1Mzc2LCJtZXJjaGFudE5vIjo4MDAyMDksIm1lcmNoYW50Q3VzdElkIjoiQ3VzdElkLTlUMTctUVhXUCIsIm5vdGlmaWNhdGlvbkVtYWlsIjpudWxsLCJhcHBJZCI6IjE3Mjc4ODA4NDYzNzg0MDE3OTIifQ==",
"subscriptionStatus": "active",
"dataStatus": "1",
"products": "[{\"currency\":\"USD\",\"name\":\"feijoa\",\"num\":\"86\",\"price\":\"620.59\",\"type\":\"nulla est\"},{\"currency\":\"USD\",\"name\":\"bush tomato\",\"num\":\"63\",\"price\":\"976.59\",\"type\":\"cillum eiusmod pariatur sed deserunt\"}]",
"channelRequestId": "8002091910535895421947905",
"scenarios": "SUBSCRIPTION_RENEWAL"
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
json
{
"//": "支付失败通知",
"notifyType": "TXN",
"transactionId": 1848240718670594048,
"txnType": "SALE",
"merchantNo": 800209,
"merchantTxnId": "1729489862000",
"originMerchantTxnId": null,
"responseTime": "2024-10-21 13:51:46",
"txnTime": "2024-10-21 13:51:40",
"txnTimeZone": "+08:00",
"orderAmount": "60.00",
"orderCurrency": "USD",
"settleRate": null,
"txnAmount": null,
"txnCurrency": null,
"customsDeclarationAmount": null,
"customsDeclarationCurrency": null,
"status": "F",
"contractId": null,
"tokenId": null,
"tokenExpireTime": null,
"cardTokenId": null,
"cardTokenExpireTime": null,
"eci": null,
"creditCard": null,
"cardBinCountry": "US",
"reason":"{\"respCode\":\"70002\",\"respMsg\":\"Unknown decline\"}"
}
1
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
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
json
{
"//": "退款通知",
"notifyType":"TXN",
"transactionId":"1600000893212209152",
"txnType":"REFUND",
"merchantNo":"800096",
"merchantTxnId":"1670304250000",
"originMerchantTxnId":"1670304250000",
"responseTime":"2022-12-06 13:36:06",
"txnTime":null,
"txnTimeZone":"+08:00",
"orderAmount":"16.00",
"orderCurrency":"USD",
"txnAmount":"16.00",
"txnCurrency":"USD",
"settleRate":"1",
"customsDeclarationAmount":null,
"customsDeclarationCurrency":null,
"status":"S",
"contractId":null,
"tokenId":null,
"tokenExpireTime":null,
"eci":null,
"reason":"{\"respCode\":\"20000\",\"respMsg\":\"Success\"}",
"periodValue":null,
"paymentMethod":"VISA",
"walletTypeName":null,
"sign": "..."
}
1
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
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
json
{
"//": "交易取消通知",
"notifyType":"CANCEL",
"transactionId":"1600013917075582976",
"txnType":"SALE",
"merchantNo":"800058",
"merchantTxnId":"1670308019000",
"originMerchantTxnId":null,
"responseTime":null,
"txnTime":"2022-12-06 14:26:59",
"txnTimeZone":null,
"orderAmount":"323.90",
"orderCurrency":"USD",
"txnAmount":"",
"txnCurrency":null,
"settleRate":null,
"customsDeclarationAmount":null,
"customsDeclarationCurrency":null,
"status":"S",
"contractId":null,
"tokenId":null,
"tokenExpireTime":null,
"eci":null,
"reason":"{\"respCode\":\"20000\",\"respMsg\":\"Success\"}",
"periodValue":null,
"paymentMethod":null,
"walletTypeName":null,
"sign": "..."
}
1
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
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
json
{
"//": "退款审核结果通知",
"notifyType":"REFUND_AUDIT",
"transactionId":"1605750169942548480",
"txnType":null,
"merchantNo":"800058",
"merchantTxnId":null,
"originMerchantTxnId":null,
"responseTime":null,
"txnTime":null,
"txnTimeZone":null,
"orderAmount":"",
"orderCurrency":null,
"txnAmount":"",
"txnCurrency":null,
"customsDeclarationAmount":null,
"customsDeclarationCurrency":null,
"status":"F",
"contractId":null,
"tokenId":null,
"tokenExpireTime":null,
"eci":null,
"reason":null,
"periodValue":null,
"paymentMethod":null,
"walletTypeName":null,
"sign": "..."
}
1
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
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
json
{
"//": "拒付通知",
"notifyType": "CHARGEBACK",
"merchantNo": "800096",
"transactionId": "1599959226371321856",
"originTransactionId": "1599953668994019328",
"originMerchantTxnId": "1670293654000",
"importTime": "2022-12-06 10:49:40",
"chargebackDate": "2022-12-06",
"chargebackAmount": "2.00",
"chargebackCurrency": "USD",
"chargebackStatus": "NEW",
"chargebackArn": "555",
"chargebackCode": "res1206CODE",
"chargebackReason": "res1206",
"appealDueTime": "2023-03-06 10:49:40",
"sign": "..."
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
您的订单需要通过异步通知来判断是否成功,并以此为依据修改您后台的订单状态。必须以异步通知通知为准。 需要注意的是 退款审核通知 只会在退款审核失败的情况下才会发送异步通知。