两方支付
PCI 合规要求
两方支付集成需要 PCI DSS 合规性,因为它涉及直接处理敏感的卡数据。商户必须:
- 持有有效的 PCI DSS 认证
- 安全地收集和传输持卡人数据
- 不得存储敏感的认证数据(例如
CVV码) - 实施适当的加密和安全措施
API 请求参数
| Parameter | Type | Length | Required | Signed | Description |
|---|---|---|---|---|---|
billingInformation | String | / | Yes | Yes | Transaction billing information in JSON string format. See TransactionAddressfor complete structure. |
cardInfo | String | / | Conditional | Yes | Card payment information in JSON string format. See TxnCardInfofor complete structure. |
merchantNo | String | 20 | Yes | Yes | Merchant number assigned by |
merchantTxnId | String | 64 | Yes | Yes | Unique transaction identifier for each customer payment, generated by the merchant system. |
merchantTxnOriginalId | String | 128 | No | Yes | Master transaction ID generated by merchant for grouping related transactions. |
merchantTxnTime | String | / | No | Yes | Transaction timestamp when the merchant initiated the transaction. |
merchantTxnTimeZone | String | 64 | No | Yes | Transaction timezone offset for the merchant transaction time. |
mpiInfo | String | / | Conditional | Yes | 3DS verification result information in JSON string format. See MpiInfofor complete structure. |
orderAmount | String | 19 | Yes | Yes | Transaction amount in the specified currency, formatted as a decimal string. |
orderCurrency | String | 8 | Yes | Yes | |
osType | String | 16 | Conditional | Yes | Operating system type for mobile and app-based transactions. See OsTypeEnumfor available options. |
paymentMode | String | 16 | No | Yes | Payment mode indicating the platform or environment for the transaction. See PaymentModeEnumfor all available options. |
paymentMethodOptions | String | / | No | Yes | Payment method configuration options in JSON string format. See PaymentMethodOptionsfor structure. |
productType | String | 16 | Yes | Yes | Payment method category that determines which payment options are available to customers. See ProductTypefor all available options. |
risk3dsStrategy | String | 16 | Conditional | Yes | 3DS risk control strategy for fraud prevention. See Risk3dsStrategyEnumfor available options. |
shippingInformation | String | / | Yes | Yes | Transaction shipping information in JSON string format. See TransactionAddressfor complete structure. |
sign | String | / | Yes | No | Digital signature string for request verification and security. Please refer to Signature for signature generation method. |
subProductType | String | 16 | Yes | Yes | Specific implementation method within the selected product type, defining how the payment is processed. See SubProductTypeEnumfor all available options. |
txnOrderMsg | String | / | Yes | Yes | Transaction business information in JSON string format. See TxnOrderMsgfor complete structure. |
txnType | String | 16 | Yes | Yes | Transaction type that defines the payment operation to be performed. See TxnTypeEnumfor all available options and detailed usage scenarios. |
TransactionAddress
| Name | Type | Length | Required | Signature | Description |
|---|---|---|---|---|---|
firstName | String | 64 | No | No | Customer first name. |
lastName | String | 64 | No | No | Customer last name. |
jpFirstName | String | 64 | No | No | First name in Japanese Katakana. |
jpLastName | String | 64 | No | No | Last name in Japanese Katakana. |
phone | String | 32 | No | No | Customer phone number in international format. |
String | 256 | Yes | No | Customer email address. | |
postalCode | String | 32 | No | No | Postal/ZIP code. |
address | String | 256 | No | No | Full address in a single field. |
country | String | 64 | Yes | No | |
province | String | 64 | Conditional | No | |
city | String | 64 | No | No | City name. |
street | String | 64 | No | No | Street name. |
number | String | 64 | No | No | House/Building number. |
identityNumber | String | 64 | No | No | Government-issued ID number. |
birthDate | String | 64 | No | No | Birth date in |
TxnCardInfo
| Name | Type | Length | Required | Description |
|---|---|---|---|---|
holderName | String | 48 | Yes | Cardholder name |
cardNumber | String | 128 | Yes | Card number |
month | String | 64 | Yes | Expiry month |
year | String | 64 | Yes | Expiry year |
cvv | String | 64 | Yes | Card CVV |
MpiInfo
| Name | Type | Length | Required | Signature | Description |
|---|---|---|---|---|---|
eci | String | 2 | Yes | No | Electronic Commerce Indicator (ECI). |
cavv | String | 128 | Yes | No | Cardholder Authentication Verification Value (CAVV). |
xid | String | 128 | No | No | 3D-Secure v1 transaction identifier. |
dsTransID | String | 128 | No | No | 3D-Secure v2 transaction identifier. |
TxnOrderMsg
| Name | Type | Length | Required | Signature | Description |
|---|---|---|---|---|---|
returnUrl | String | 256 | Yes | No | Synchronous return address. After payment completion, customer is redirected to this URL |
products | String | 1024 | Yes | No | List of product information purchased by the customer See Productsfor complete structure. |
transactionIp | String | 64 | Conditional | No | Cardholder transaction |
appId | String | 20 | Yes | No | Store |
javaEnabled | Boolean | / | Conditional | No | Whether the cardholder's browser has |
colorDepth | String | 64 | Conditional | No | Cardholder screen color depth, retrieved via: |
screenHeight | String | 64 | Conditional | No | Cardholder's screen resolution, retrieved via: |
screenWidth | String | 64 | Conditional | No | Cardholder's screen resolution, retrieved via: |
timeZoneOffset | String | 64 | Conditional | No | Cardholder browser's time zone, retrieved via: |
accept | String | 2048 | Conditional | No | Cardholder browser's |
userAgent | String | 2048 | Conditional | No | Cardholder's browser type, retrieved via: |
contentLength | String | 64 | Conditional | No | Content length of the cardholder's browser content beyond the headers |
customerPlatform | String | 128 | Conditional | No | Merchant platform identifier |
language | String | 64 | Conditional | No | Cardholder's browser language, retrieved via: |
periodValue | String | / | Conditional | No | Installment payment period. |
notifyUrl | String | 256 | Yes | No |
Products
| Name | Type | Length | Required | Description |
|---|---|---|---|---|
name | String | 256 | Yes | Product name |
price | String | 1024 | Yes | Product unit price |
num | String | 20 | Yes | Product quantity |
productAvatarUrl | String | 255 | Conditional | Product image URL |
desc | String | 1024 | No | Product description |
currency | String | 256 | Yes | Currency code following ISO 4217 standard |
type | String | 256 | Conditional | Product category. See StoreProductTypeEnum |
products 必须为 JSON 字符串格式
示例:
如果type为discount,折扣金额应作为负数传递\"[{\\\"name\\\":\\\"Pro1\\\",\\\"price\\\":\\\"50.00\\\",\\\"num\\\":\\\"2\\\",\\\"currency\\\":\\\"USD\\\"},{\\\"name\\\":\\\"Pro2\\\",\\\"price\\\":\\\"100\\\",\\\"num\\\":\\\"1\\\",\\\"currency\\\":\\\"USD\\\"}]\"\"[{\\\"name\\\":\\\"Pro1\\\",\\\"price\\\":\\\"50.00\\\",\\\"num\\\":\\\"2\\\",\\\"currency\\\":\\\"USD\\\"},{\\\"name\\\":\\\"Pro2\\\",\\\"price\\\":\\\"100\\\",\\\"num\\\":\\\"1\\\",\\\"currency\\\":\\\"USD\\\"},{\\\"name\\\":\\\"discount\\\",\\\"price\\\":\\\"-10\\\",\\\"num\\\":\\\"1\\\",\\\"currency\\\":\\\"USD\\\",\\\"type\\\":\\\"discount\\\"}]\"\"[{\\\"name\\\":\\\"Pro1\\\",\\\"price\\\":\\\"50.00\\\",\\\"num\\\":\\\"2\\\",\\\"currency\\\":\\\"USD\\\"},{\\\"name\\\":\\\"Pro2\\\",\\\"price\\\":\\\"100\\\",\\\"num\\\":\\\"1\\\",\\\"currency\\\":\\\"USD\\\"},{\\\"name\\\":\\\"shipping fee\\\",\\\"price\\\":\\\"10\\\",\\\"num\\\":\\\"1\\\",\\\"currency\\\":\\\"USD\\\",\\\"type\\\":\\\"shipping_fee\\\"}]\"\"[{\\\"name\\\":\\\"Pro1\\\",\\\"price\\\":\\\"50.00\\\",\\\"num\\\":\\\"2\\\",\\\"currency\\\":\\\"USD\\\"},{\\\"name\\\":\\\"Pro2\\\",\\\"price\\\":\\\"100\\\",\\\"num\\\":\\\"1\\\",\\\"currency\\\":\\\"USD\\\"},{\\\"name\\\":\\\"shipping fee\\\",\\\"price\\\":\\\"10\\\",\\\"num\\\":\\\"1\\\",\\\"currency\\\":\\\"USD\\\",\\\"type\\\":\\\"shipping_fee\\\"},{\\\"name\\\":\\\"discount\\\",\\\"price\\\":\\\"-10\\\",\\\"num\\\":\\\"1\\\",\\\"currency\\\":\\\"USD\\\",\\\"type\\\":\\\"discount\\\"}]\"\"[{\\\"name\\\":\\\"Pro1\\\",\\\"price\\\":\\\"50.00\\\",\\\"num\\\":\\\"2\\\",\\\"currency\\\":\\\"USD\\\",\\\"type\\\":\\\"physical\\\"},{\\\"name\\\":\\\"Pro2\\\",\\\"price\\\":\\\"100\\\",\\\"num\\\":\\\"1\\\",\\\"currency\\\":\\\"USD\\\",\\\"type\\\":\\\"physical\\\"}]\"\"[{\\\"name\\\":\\\"游戏点数\\\",\\\"price\\\":\\\"25.00\\\",\\\"num\\\":\\\"1\\\",\\\"currency\\\":\\\"USD\\\",\\\"type\\\":\\\"virtual\\\"},{\\\"name\\\":\\\"高级会员\\\",\\\"price\\\":\\\"49.99\\\",\\\"num\\\":\\\"1\\\",\\\"currency\\\":\\\"USD\\\",\\\"type\\\":\\\"virtual\\\"}]\"注意:price * num (商品金额) + price * num (折扣金额) + price * num (运费) = orderAmount (订单交易金额)
响应参数
| Name | Type | Description |
|---|---|---|
respCode | String | Response code from |
respMsg | String | Response message from |
data | Object | Response data. Refer to object data |
data
| Name | Type | Description |
|---|---|---|
transactionId | String | Transaction order number created by |
responseTime | String | Interface response time Format: |
txnTime | String | Transaction completion time Format: |
txnTimeZone | String | Transaction time zone Format: |
orderAmount | String | Order amount |
orderCurrency | String | |
txnAmount | String | Order amount after conversion to settlement currency |
txnCurrency | String | |
status | String | Transaction processing result Refer to TxnStatusEnum |
redirectUrl | String | Redirection URL for 3D Secure verification |
contractId | String | Subscription contract number |
tokenId | String | Payment token |
eci | String | Electronic Commerce Indicator |
periodValue | String | Installment payment number of periods |
codeForm | String | Code form for specific payment methods See CodeFormEnum |
presentContext | String | Context information for presentation layer |
actionType | String | Action type for the transaction See ActionTypeEnum |
subscriptionManageUrl | String | Subscription management URL |
sign | String |
两方支付集成流程
两方支付集成流程包含三个主要阶段,如下图所示:
1. 支付发起
在此阶段:
- 顾客在商户的网站/应用程序上输入支付信息(自定义 UI)
- 商户系统安全地收集支付数据并传输给 Onerway
- 支付请求在
cardInfo参数中包含敏感的卡数据 - 商户负责设计一个安全、用户友好的支付表单
2. 支付处理
在此阶段:
- Onerway 处理支付请求并确定是否需要 3DS 验证
- 如果不需要 3DS,Onerway 立即返回支付结果
- 如果需要 3DS:
- Onerway 返回
status=R和一个redirectUrl指向 3DS 验证页面 - 商户必须将顾客重定向以完成 3DS 验证
- 验证后,Onerway 通过 webhook 发送最终支付结果
- Onerway 返回
3. 支付结果通知
在此阶段:
- Onerway 通过 HTTP
POST将详细的支付结果数据发送到notifyUrl - webhook 包含完整的交易信息,包括
transactionId、status、paymentMethod和用于验证的signature - 商户系统必须响应
transactionId以确认收到 webhook - 如果未收到成功响应,Onerway 将以 30 分钟的间隔重试发送 webhook,最多重试
3次
3DS 处理
在实施两方支付时,商户必须正确处理 3DS 认证流程:
3DS认证处理
当响应包含status=R和actionType=RedirectURL时,商户必须将客户重定向以完成3DS验证:
{
"data": {
"status": "R",
"redirectUrl": "https://sandbox-3ds.onerway.com/...",
"actionType": "RedirectURL"
}
}2
3
4
5
6
7
重要提醒
txnOrderMsg中的returnUrl参数对于3DS流程至关重要:
- 必须是您网站上能够处理返回客户的有效URL
- 3DS验证完成后,客户浏览器将被重定向到此URL
- 交易状态参数将作为查询参数附加到URL中
最佳实践
实施交易状态跟踪机制来处理3DS验证后的异步支付完成。您的returnUrl端点应该:
- 从URL参数中提取交易ID和状态
- 向客户显示适当的消息
- 如需要,通过服务器检查交易状态
3DS流程示例代码
1. 检测3DS要求
function handle3DSResponse(response) {
if (
response.data.status === 'R' &&
response.data.actionType === 'RedirectURL'
) {
// 需要3DS验证
window.location.href = response.data.redirectUrl
} else if (response.data.status === 'S') {
// 支付成功,无需3DS
handlePaymentSuccess(response.data)
} else {
// 支付失败
handlePaymentFailure(response.data)
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
2. 配置returnUrl处理
// 在支付请求中设置returnUrl
const txnOrderMsg = {
returnUrl: 'https://yoursite.com/payment/return',
notifyUrl: 'https://yoursite.com/webhook/payment'
}
// returnUrl页面处理逻辑
function handlePaymentReturn() {
const urlParams = new URLSearchParams(window.location.search)
const transactionId = urlParams.get('transactionId')
const status = urlParams.get('status')
if (status === 'S') {
showSuccessMessage('支付成功!')
// 可选:服务器端验证交易状态
verifyTransactionStatus(transactionId)
} else {
showErrorMessage('支付未完成,请重试。')
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
3. 服务器端状态验证
async function verifyTransactionStatus(transactionId) {
try {
const response = await fetch('/api/verify-payment', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ transactionId })
})
const result = await response.json()
if (result.status === 'S') {
// 确认支付成功,更新订单状态
updateOrderStatus(result.merchantTxnId, 'PAID')
}
} catch (error) {
console.error('验证支付状态失败:', error)
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
3DS错误处理
常见3DS错误场景
function handle3DSErrors(response) {
switch (response.respCode) {
case '40201':
// 3DS验证失败
showMessage('身份验证失败,请重试', 'error')
break
case '40202':
// 3DS超时
showMessage('验证超时,请重新发起支付', 'warning')
break
case '40203':
// 银行拒绝3DS
showMessage('银行拒绝验证,请联系银行或使用其他卡片', 'error')
break
default:
showMessage('支付过程中发生错误,请重试', 'error')
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
移动端3DS处理
原生应用中的3DS处理
// React Native示例
import { WebView } from 'react-native-webview'
function ThreeDSWebView({ redirectUrl, onComplete }) {
const handleNavigationStateChange = (navState) => {
// 检查是否返回到returnUrl
if (navState.url.includes('yoursite.com/payment/return')) {
const urlParams = new URLSearchParams(navState.url.split('?')[1])
const status = urlParams.get('status')
const transactionId = urlParams.get('transactionId')
onComplete({ status, transactionId })
}
}
return (
<WebView
source={{ uri: redirectUrl }}
onNavigationStateChange={handleNavigationStateChange}
javaScriptEnabled={true}
domStorageEnabled={true}
/>
)
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
3DS测试卡号
沙盒环境测试卡号
const test3DSCards = {
// 成功3DS验证
success: '4000000000001091',
// 3DS验证失败
failure: '4000000000001109',
// 3DS超时
timeout: '4000000000001117',
// 无需3DS验证
no3DS: '4242424242424242'
}
// 测试用例
function test3DSFlow(cardNumber) {
const testPayload = {
merchantNo: '800000',
merchantTxnId: `test_3ds_${Date.now()}`,
orderAmount: '100.00',
orderCurrency: 'USD',
txnType: 'SALE',
cardInfo: `{"cardNo":"${cardNumber}","expMonth":"12","expYear":"2025","cvv":"123"}`,
txnOrderMsg: `{"returnUrl":"https://yoursite.com/test/return","notifyUrl":"https://yoursite.com/test/webhook"}`
}
// 发送支付请求
return sendPaymentRequest(testPayload)
}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
监控和日志
3DS相关指标监控
const threeDSMetrics = {
total3DSRequests: 0,
successful3DS: 0,
failed3DS: 0,
timeout3DS: 0,
recordAttempt(result) {
this.total3DSRequests++
switch (result) {
case 'success':
this.successful3DS++
break
case 'failure':
this.failed3DS++
break
case 'timeout':
this.timeout3DS++
break
}
},
getSuccessRate() {
return this.successful3DS / this.total3DSRequests
}
}
// 记录3DS尝试
function log3DSAttempt(transactionId, result, details) {
console.log('3DS验证尝试', {
transactionId,
result,
timestamp: new Date().toISOString(),
userAgent: navigator.userAgent,
// 不记录敏感信息
details: {
duration: details.duration,
redirectCount: details.redirectCount
}
})
threeDSMetrics.recordAttempt(result)
}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
API 使用示例
标准支付请求(无 3DS)
{
"billingInformation": "{\"address\":\"78732 Manor Way\",\"city\":\"Carlsbad\",\"country\":\"US\",\"email\":\"Patience.Tremblay@yahoo.com\",\"firstName\":\"Jammie\",\"identityNumber\":\"66040505850\",\"lastName\":\"Walter\",\"phone\":\"13804962361\",\"postalCode\":\"80787-0866\",\"province\":\"CO\"}",
"cardInfo": "{\"holderName\":\"CL BRW2\",\"cardNumber\":\"4000000000002701\",\"month\":\"05\",\"year\":\"26\",\"cvv\":\"123\"}",
"merchantCustId": "CustId-DZJ4-P0KW",
"merchantNo": "800209",
"merchantTxnId": "2ce8fca1-f380-4c60-85ef-68a3a0c76ece",
"merchantTxnTime": "2025-05-06 15:15:52",
"orderAmount": "5",
"orderCurrency": "USD",
"productType": "CARD",
"shippingInformation": "{\"address\":\"251 Clark Street\",\"city\":\"Elmhurst\",\"country\":\"US\",\"email\":\"Lilly_OKon43@gmail.com\",\"firstName\":\"Tyrell\",\"identityNumber\":\"07830885514\",\"lastName\":\"Hettinger\",\"phone\":\"15164105025\",\"postalCode\":\"25067-9128\",\"province\":\"CO\"}",
"paymentMethodOptions": "{\"card\":{\"avsEnabled\":true}}", // 可选:开启 AVS 验证
"sign": "0284bc8fdc89ef5429017ddae286984f81fb18aa95c6e752c35ed910c3af9f96",
"subProductType": "DIRECT",
"txnOrderMsg": "{\"accept\":\"*/*\",\"appId\":\"1727880846378401792\",\"colorDepth\":\"24\",\"contentLength\":\"0\",\"javaEnabled\":true,\"language\":\"en-US\",\"products\":\"[{\\\"currency\\\":\\\"USD\\\",\\\"name\\\":\\\"banana\\\",\\\"num\\\":\\\"89\\\",\\\"price\\\":\\\"340.29\\\",\\\"type\\\":\\\"incididunt dolore Duis nostrud officia\\\"},{\\\"currency\\\":\\\"USD\\\",\\\"name\\\":\\\"watermelon\\\",\\\"num\\\":\\\"23\\\",\\\"price\\\":\\\"611.69\\\",\\\"type\\\":\\\"commodo Duis sint\\\"},{\\\"currency\\\":\\\"USD\\\",\\\"name\\\":\\\"berry\\\",\\\"num\\\":\\\"99\\\",\\\"price\\\":\\\"592.95\\\",\\\"type\\\":\\\"fugiat exercitation proident sunt ut\\\"}]\",\"returnUrl\":\"https://docs.onerway.com/\",\"notifyUrl\":\"https://docs.onerway.com/apis\",\"screenHeight\":\"800\",\"screenWidth\":\"2048\",\"timeZoneOffset\":\"540\",\"transactionIp\":\"110.89.6.86\",\"userAgent\":\"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36\"}",
"txnType": "SALE"
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"respCode": "20000",
"respMsg": "Success",
"data": {
"transactionId": "1919652333131005952",
"responseTime": "2025-05-06 15:16:00",
"txnTime": "2025-05-06 15:15:56",
"txnTimeZone": "+08:00",
"orderAmount": "5.00",
"orderCurrency": "USD",
"txnAmount": null,
"txnCurrency": null,
"status": "S", // 立即成功,无需 3DS
"redirectUrl": null,
"contractId": null,
"tokenId": null,
"eci": null,
"periodValue": null,
"codeForm": null,
"presentContext": null,
"actionType": null,
"subscriptionManageUrl": null,
"sign": "e9607be76267352004f0e20065361f2fcd415bbb5121f002c104bdda11f68a4d"
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
"notifyType": "TXN",
"transactionId": "1919652333131005952",
"txnType": "SALE",
"merchantNo": "800209",
"merchantTxnId": "2ce8fca1-f380-4c60-85ef-68a3a0c76ece",
"responseTime": "2025-05-06 15:16:00",
"txnTime": "2025-05-06 15:15:56",
"txnTimeZone": "+08:00",
"orderAmount": "5.00",
"orderCurrency": "USD",
"status": "S",
"cardBinCountry": "US",
"reason": "{\"respCode\":\"20000\",\"respMsg\":\"Success\"}",
"sign": "ff999833f72c5a5875af7fa797020cfb83f9ca1f7408b2a4c85c039f835e6c62",
"paymentMethod": "VISA",
"channelRequestId": "8002091919652333131005952"
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
3DS 支付请求
{
"billingInformation": "{\"address\":\"78732 Manor Way\",\"city\":\"Carlsbad\",\"country\":\"US\",\"email\":\"Patience.Tremblay@yahoo.com\",\"firstName\":\"Jammie\",\"identityNumber\":\"66040505850\",\"lastName\":\"Walter\",\"phone\":\"13804962361\",\"postalCode\":\"80787-0866\",\"province\":\"CO\"}",
"cardInfo": "{\"holderName\":\"CL BRW2\",\"cardNumber\":\"4000000000002701\",\"month\":\"05\",\"year\":\"26\",\"cvv\":\"123\"}",
"merchantCustId": "CustId-DZJ4-P0KW",
"merchantNo": "800209",
"merchantTxnId": "6ef8a9c7-8d54-4b01-9acf-3582e70d9b1e",
"merchantTxnTime": "2025-05-06 15:14:46",
"orderAmount": "200", // 较高金额通常会触发 3DS
"orderCurrency": "USD",
"productType": "CARD",
"shippingInformation": "{\"address\":\"251 Clark Street\",\"city\":\"Elmhurst\",\"country\":\"US\",\"email\":\"Lilly_OKon43@gmail.com\",\"firstName\":\"Tyrell\",\"identityNumber\":\"07830885514\",\"lastName\":\"Hettinger\",\"phone\":\"15164105025\",\"postalCode\":\"25067-9128\",\"province\":\"CO\"}",
"paymentMethodOptions": "{\"card\":{\"avsEnabled\":true}}", // 可选:开启 AVS 验证
"sign": "0284bc8fdc89ef5429017ddae286984f81fb18aa95c6e752c35ed910c3af9f96",
"subProductType": "DIRECT",
"txnOrderMsg": "{\"accept\":\"*/*\",\"appId\":\"1727880846378401792\",\"colorDepth\":\"24\",\"contentLength\":\"0\",\"javaEnabled\":true,\"language\":\"en-US\",\"products\":\"[{\\\"currency\\\":\\\"USD\\\",\\\"name\\\":\\\"banana\\\",\\\"num\\\":\\\"89\\\",\\\"price\\\":\\\"340.29\\\",\\\"type\\\":\\\"incididunt dolore Duis nostrud officia\\\"},{\\\"currency\\\":\\\"USD\\\",\\\"name\\\":\\\"watermelon\\\",\\\"num\\\":\\\"23\\\",\\\"price\\\":\\\"611.69\\\",\\\"type\\\":\\\"commodo Duis sint\\\"},{\\\"currency\\\":\\\"USD\\\",\\\"name\\\":\\\"berry\\\",\\\"num\\\":\\\"99\\\",\\\"price\\\":\\\"592.95\\\",\\\"type\\\":\\\"fugiat exercitation proident sunt ut\\\"}]\",\"returnUrl\":\"https://docs.onerway.com/\",\"notifyUrl\":\"https://docs.onerway.com/apis\",\"screenHeight\":\"800\",\"screenWidth\":\"2048\",\"timeZoneOffset\":\"540\",\"transactionIp\":\"110.89.6.86\",\"userAgent\":\"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36\"}",
"txnType": "SALE"
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"respCode": "20000",
"respMsg": "Success",
"data": {
"transactionId": "1919652057678479360",
"responseTime": "2025-05-06 15:14:53",
"txnTime": "2025-05-06 15:14:50",
"txnTimeZone": "+08:00",
"orderAmount": "200.00",
"orderCurrency": "USD",
"txnAmount": null,
"txnCurrency": null,
"status": "R", // 需要 3DS 验证
"redirectUrl": "https://sandbox-gw-dmz.onerway.com/3dsSecure/direct/RDT_3DS_DDC_8002091919652062199676929", // 3DS 验证 URL
"contractId": null,
"tokenId": null,
"eci": null,
"periodValue": null,
"codeForm": null,
"presentContext": null,
"actionType": "RedirectURL", // 表示需要重定向
"subscriptionManageUrl": null,
"sign": "7bad919d6fd128782626b2582873dc68417fc67df2fc45542164613fa7f472b2"
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
"notifyType": "TXN",
"transactionId": "1919652057678479360",
"txnType": "SALE",
"merchantNo": "800209",
"merchantTxnId": "6ef8a9c7-8d54-4b01-9acf-3582e70d9b1e",
"responseTime": "2025-05-06 15:17:42",
"txnTime": "2025-05-06 15:14:50",
"txnTimeZone": "+08:00",
"orderAmount": "200.00",
"orderCurrency": "USD",
"status": "S", // 3DS 验证后的最终状态
"eci": "05", // ECI 值表示 3DS 认证结果
"cardBinCountry": "US",
"reason": "{\"respCode\":\"20000\",\"respMsg\":\"Success\"}",
"sign": "8a73b542c9d2e8f6b70c49a3ef1d8c7654d6fb12e0385a17fb9ea427c85b3f9d",
"paymentMethod": "VISA",
"channelRequestId": "8002091919652062199676929"
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
常见错误场景和解决方案
实施最佳实践
- PCI 合规性:维护并定期更新您的 PCI DSS 认证
- 安全传输:始终使用 TLS 加密并实施适当的安全措施
- 3DS 处理:正确处理 3DS 重定向并通过 webhook 验证最终支付状态
- Webhook 验证:始终验证 webhook 签名以防止篡改
- 错误处理:实施强大的错误处理机制并向顾客提供清晰的消息
- 交易跟踪:维护交易日志以便对账和故障排除
- 欺诈预防:实施适当的欺诈检测机制并收集设备指纹数据
- 幂等性:幂等地处理 webhook 通知以应对潜在的重复通知
商户集成清单
在上线两方支付集成之前,请确保您已:
- 有效的 PCI DSS 认证
- 安全的卡数据收集表单
- 适当的错误处理机制
- 3DS 重定向处理实现
- Webhook 处理和验证
- 交易状态跟踪系统
- 在沙箱环境中进行彻底测试