Web SDK 接入分为两部分:服务端创建支付并保存订单与 paymentId 的映射,浏览器加载 SDK 并使用该 paymentId 创建 Checkout。secret、请求签名、客户身份映射和最终支付状态确认始终保留在服务端。
开始前,先按接入准备获取 API 凭证,并将服务端的公网出口 IP 加入对应环境的白名单。每个请求都需按请求签名生成 sign。上线前,参考沙盒测试在沙盒环境验证集成中使用的全部场景。
Web SDK 使用 Onerway 的 Google Pay 能力,无需报备网站;网站报备仅适用于 API 直连接入。
接入流程
- 服务端调用创建 SDK 交易,保存返回的
paymentId。 - 浏览器加载与交易环境匹配的 CDN 脚本。
- 使用
paymentId创建 Checkout,先订阅事件,再挂载 Payment Element。 - Card、本地支付和其他自定义支付按钮调用
confirmPayment();Apple Pay、Google Pay 等 SDK 自有按钮只监听payment_result。 - 客户端根据事件更新页面;服务端通过查询支付记录或支付 Webhook 确认最终状态。
在服务端创建支付
普通 Web SDK v4 支付应通过创建 SDK 交易传入 productType=ALL、subProductType=DIRECT 和 txnType=SALE。标准的一次性扣款示例省略了 billingInformation、shippingInformation、paymentMode 和 osType。
创建交易时,billingInformation 与 shippingInformation 均为可选。信息已具备时即可传入;初始下单省略且业务流程需要时,可以在确认支付前通过更新 SDK 订单补充。传入对象后,其内部字段原有的必填条件仍然生效。更新订单时,服务端应复用原下单的 merchantTxnId,并在客户确认支付前等待更新成功响应。
当前 Web SDK 的字段 txnOrderMsg只包含 returnUrl、products、appId、customerPlatform、periodValue 和 notifyUrl;每个字段是否必填及其适用条件以 API Reference 为准。商户服务端不要采集或传入浏览器、设备和持卡人 IP 字段,这些信息由 Web SDK 采集。
Web SDK 支付通常省略 paymentMode,无需区分桌面和移动浏览器。传入非 WEB 值时,必须同时传入 osType。
服务端只把创建支付响应中的 paymentId 传给浏览器。transactionId 可用于服务端订单关联,但不能替代 paymentId 初始化 SDK。响应仍会返回 redirectUrl,当前 Web SDK 初始化时不消费该字段。
加载 SDK
CDN 与 environment 必须匹配:
| 环境 | CDN | environment |
|---|---|---|
| Sandbox | https://sandbox-checkout-sdk.onerway.com/v4/latest/onerway.js | sandbox |
| Production | https://checkout-sdk.onerway.com/v4/latest/onerway.js | production,默认值 |
v4/latest 是 Production 正式推荐的长期地址。即使 environment 默认为 production,也建议显式传入,避免复制配置时混用环境。
<script src="https://checkout-sdk.onerway.com/v4/latest/onerway.js"></script>
<div id="onerway_checkout"></div>
<button id="pay_button" type="button">Pay now</button>
初始化、订阅事件并挂载
const checkout = await Onerway.createCheckout(paymentId, {
environment: 'production',
locale: 'en'
})
const paymentElement = checkout.createPaymentElement()
paymentElement.on('ready', (event) => {
console.log(event.availablePaymentMethods)
})
paymentElement.on('loaderror', (event) => {
console.error(event.error.code, event.error.message)
})
checkout.on('payment_result', handlePaymentResult)
paymentElement.mount('#onerway_checkout')
必须先订阅事件,再调用 mount():
ready.availablePaymentMethods是当前订单、服务端配置和浏览器钱包能力共同决定的可用支付方式列表。不要把示例值当成固定枚举;钱包不可用时 SDK 会隐藏相应按钮。loaderror只表示 Checkout 初始化失败。程序逻辑应判断event.error.code,event.error.message仅用于展示。公开的 code 只有两个:checkout_load_failed(首次加载支付方式失败,可让客户重新初始化)和no_available_payment_methods(过滤后没有可展示的支付方式,检查服务端配置与paymentMethod)。- 表单校验、支付接口失败、钱包取消和 3DS/外跳异常不属于
loaderror,应从confirmPayment()返回值或payment_result处理。
配置 Payment Element
config 的子字段均为可选,但商户应根据自己的支付方式、表单和品牌要求决定是否传入,不能假定所有业务都使用默认展示。配置在 paymentElement.mount() 时读取;修改后需要重新创建并挂载 Payment Element 才能生效。
| 字段 | 类型 | 默认值 | 作用 |
|---|---|---|---|
paymentMethod | String[] | 不传 | 支付方式显示白名单,只保留服务端实际返回且存在于数组中的方式 |
showBillingAddress | Boolean | true | 是否展示并校验账单地址表单 |
displayCardholdername | Boolean | true | 是否展示并校验持卡人姓名输入框 |
walletButtons | Object | 见下文 | 配置 Apple Pay 和 Google Pay 官方按钮支持的外观 |
checkoutTheme | String | light | SDK 主题预设;当前公开主题只有 light |
variables | Object | {} | 覆盖主题变量,建议优先使用 |
styles | Object | {} | 按 CSS selector 覆盖 SDK 样式,优先级最高 |
customCssURL | String | SDK 默认 CSS | 替换 SDK 基础样式表来源;variables 和 styles 仍然生效 |
例如,商户可以只展示当前业务接受的方式、隐藏 SDK 账单地址表单,并对 SDK 可控区域应用品牌样式:
const checkout = await Onerway.createCheckout(paymentId, {
environment: 'production',
locale: 'en',
config: {
paymentMethod: ['CARD', 'DOKU_VA', 'GooglePay'],
showBillingAddress: false,
displayCardholdername: true,
checkoutTheme: 'light',
variables: {
colorPrimary: '#2563eb',
colorText: '#1a202c',
borderRadius: '8px'
},
walletButtons: {
googlePay: { type: 'pay', color: 'black', height: '44px' },
applePay: { type: 'pay', color: 'black', height: '44px' }
}
}
})
限制支付方式
paymentMethod 只负责前端显示过滤,不会为商户开通支付方式:
| 传值 | 行为 |
|---|---|
| 不传 | 展示服务端返回且当前设备可用的全部方式 |
['CARD', 'FPX', 'GooglePay'] | 只展示服务端也返回的 CARD、FPX 和 GooglePay |
[] | 不展示任何方式,并触发 loaderror;event.error.code 为 no_available_payment_methods |
数组值必须与服务端返回的支付方式标识完全一致。数组顺序不控制展示顺序;实际顺序仍由服务端支付方式配置和 SDK 钱包区域决定。是否成功加载某种方式,最终以 ready.availablePaymentMethods 为准。
配置表单显示
showBillingAddress: false会隐藏账单地址并停止相应的前端校验,但不会修改 Create transaction 或 Update order 的服务端字段约束。需要账单信息的业务应在确认支付前自行采集并更新订单。displayCardholdername: false会隐藏持卡人姓名并停止相应的前端校验。
配置钱包按钮
| 字段 | 默认值 | 支持值或规则 |
|---|---|---|
googlePay.type | pay | book, buy, checkout, donate, order, pay, plain, subscribe |
googlePay.color | black | black, white |
applePay.type | pay | add-money, book, buy, check-out, continue, contribute, donate, order, plain, reload, rent, subscribe, support, tip, top-up, pay |
applePay.color | black | black, white, white-outline |
googlePay.width / applePay.width | 100% | CSS 尺寸字符串 |
googlePay.height / applePay.height | 44px | CSS 尺寸字符串 |
googlePay.radius / applePay.radius | 8px | CSS 尺寸字符串;Apple / Google 平台可能限制最终外观 |
这些选项只调整 SDK 官方钱包按钮支持的外观,不会使当前设备不支持的钱包变为可用,也不能用 variables、styles 或自定义 CSS 强制覆盖平台控制的按钮外观。Apple Pay 的域名验证等接入准备见支付方式。
配置主题与样式
checkoutTheme当前只支持light。variables是推荐的品牌定制方式。支持的常用变量包括containerBackground、cardBackground、inputBackground、inputBrandBackground、aggregateHeaderBackground、dialogBackground、colorText、colorPrimary、colorDanger、fontFamily、fontSizeBase和borderRadius。fontSizeBase支持12px–24px,borderRadius支持0px–24px。styles接收 CSS selector 到 CSS 属性对象的映射,例如{ '.onerway-checkout__input': { color: '#1a202c' } },用于变量无法覆盖的局部样式。customCssURL用于整体替换 SDK 基础样式表;之后仍可通过variables和styles覆盖。
主题和样式仅作用于 SDK 可控区域。历史配置 showPayButton 和 payButtonText 已不再支持并会被 SDK 忽略。
语言(Locale)
不传 locale 时,SDK 使用浏览器语言。显式传入的值或浏览器语言不受当前支付方式支持时,SDK 默认回退到英语 en。
普通支付方式支持以下 locale 取值(按字母序):
| 代码 | 语言 | 代码 | 语言 |
|---|---|---|---|
ar | 阿拉伯语 | de | 德语 |
en | 英语 | es | 西班牙语 |
fi | 芬兰语 | fr | 法语 |
it | 意大利语 | ja | 日语 |
ko | 韩语 | nl | 荷兰语 |
no | 挪威语 | pl | 波兰语 |
pt | 葡萄牙语 | ru | 俄语 |
sv | 瑞典语 | th | 泰语 |
zh-cn | 简体中文 | zh-tw | 繁体中文 |
钱包使用自己的 locale 枚举和大小写,两个钱包的支持范围只有以下差异:
| 支持范围 | Locale |
|---|---|
| 两个钱包都支持 | ar, ca, cs, da, de, el, en, es, fi, fr, hr, id, it, ja, ko, ms, nl, no, pl, pt, ru, sk, sv, th, tr, uk, zh |
| 仅 Google Pay | bg, et, sl, sr |
| 仅 Apple Pay | he, hi, hu, ro, vi, zh-TW |
钱包遇到不支持的 locale 时同样回退到英语 en。例如,普通支付方式的简体中文为 zh-cn,钱包为 zh;普通支付方式的繁体中文为 zh-tw,钱包为 zh-TW。不要自行转换其他未列出的值。
确认支付
Card、本地支付与自定义按钮
这些支付方式必须由商户按钮调用 confirmPayment():
document.querySelector('#pay_button').addEventListener('click', async () => {
const result = await checkout.confirmPayment()
handleConfirmResult(result)
})
不要重复创建 Checkout 或在重试时重新下单。可重试状态下,保留同一个 paymentId、Checkout 和 Payment Element。
Apple Pay、Google Pay 等 SDK 自有按钮
SDK 自有钱包按钮不能调用 confirmPayment()。用户点击 SDK 渲染的官方按钮后,只通过 payment_result 接收客户端结果:
checkout.on('payment_result', (result) => {
if (result.reason?.type === 'canceled') {
// 用户关闭钱包;恢复页面交互,不要把它映射为支付失败。
return
}
renderClientResult(result)
})
钱包是否展示还取决于服务端配置、浏览器、设备和钱包能力。
在 App 内嵌 WebView 中使用 Google Pay
Google Pay 是否可用由能力检测决定:条件不满足时 ready.availablePaymentMethods 不会包含 GooglePay,SDK 不渲染其按钮,属预期行为而非故障。
- Android WebView 官方支持 Google Pay,但需宿主 App 配合:Android WebView 137+、Google Play services 25.18.30+,集成
androidx.webkit:webkit:1.14.0、声明 Chromium payment intent actions、启用 Payment Request API,并向 Google 发布 App integration;使用自定义 User-Agent 时需附加GOOGLE_PAY_SUPPORTED。详见 Google 官方 WebView 指南。 - iOS 内嵌 WebView 不支持 Google Pay。
- 宿主 App 不具备上述条件时,可将支付流程外跳系统浏览器完成,并确保支付后引导用户返回原 App。
paymentStatus 与 nextAction
只有 paymentStatus === 'R' 时才会返回 nextAction:
nextAction.type | SDK 行为 | 商户处理 |
|---|---|---|
PresentToShopper | SDK 在当前页展示二维码、本地支付页等承接界面;此时还没有最终支付结果。 | 保留当前 Checkout,等待 payment_result,不要再次调用 confirmPayment()。 |
RedirectShopper | SDK 即将跳转到外部支付页面;此时还没有最终支付结果。3DS 使用此流程。 | 等待 Onerway 回跳到下单时的 returnUrl,再由服务端使用已保存的 paymentId 调用查询支付记录。 |
R 只表示支付流程需要继续,不代表成功或失败。nextAction 不会在 paymentStatus !== 'R' 时返回。
paymentStatus 的完整取值与定义见响应字段 paymentStatus。客户端状态只用于更新页面,不得据此发货、充值或记账:
paymentStatus | 商户处理 |
|---|---|
I、U、P、A | 非最终状态。订单保持待处理,不履约。 |
R | 进入承接或外跳流程,读取 nextAction.type 并按上表处理。 |
O | 允许继续支付或重试。保留同一个 paymentId、Checkout 和 Payment Element,不重新下单。 |
S、N | 客户端收到的结果,仍需服务端确认后再完成订单或按订单规则展示。 |
没有形成支付状态的客户端异常通过 reason 描述:
reason.type | 含义 |
|---|---|
validation_error | 本地表单校验失败,未形成支付状态 |
sdk_error | SDK 本地状态、配置或调用问题 |
api_error | 支付接口或后端业务失败;reason.code 是后端原始 respCode,参见响应码 |
canceled | 客户主动取消当前交互;reason.code 为 presenter_closed(关闭 SDK 承接的二维码或本地支付弹窗)、cvv_closed(关闭 Google Pay 授权后的二次 CVV 验证弹窗)或 wallet_canceled(取消 Apple Pay 或 Google Pay 官方授权窗) |
客户取消时可能没有 paymentStatus,只有 reason.type === 'canceled';取消前端流程不等于最终支付失败,恢复页面交互即可。
确认最终支付结果
confirmPayment() 返回值、payment_result 和 returnUrl 都只能驱动客户端页面流转,最终结果以 Webhook 为准:普通支付见支付结果通知,客户自选保存卡见保存支付方式结果通知,订阅见订阅扣款通知,预授权见预授权、请款与撤销通知。验签、应答与重试、幂等去重、状态判断与查询补偿的通用规则见 Webhook 通知。
Web SDK 接入需额外注意:服务端应保存商户订单与 paymentId 的映射;外跳回到 returnUrl 后不要相信 URL 中携带的支付状态,先把页面交互恢复为“正在确认”,未收到 Webhook 时由服务端使用 paymentId 调用查询支付记录补偿并返回业务结果。不要在浏览器日志、持久化数据或埋点中保存未脱敏的 rawResult、请求响应或支付数据。
保存卡与订阅
让客户主动选择是否保存卡
保持字段 subProductType =DIRECT 并传入稳定的字段 merchantCustId。SDK 会向客户展示保存卡选项,该选项不会默认选中;后续支付复用同一个 merchantCustId,SDK 会回显该客户的已保存卡,并在内部完成选卡和支付,客户端无需为该流程获取 tokenId。
Web SDK 接入需额外注意:subProductType=TOKEN 属于旧版 Web SDK 保存卡流程,不用于当前 Web SDK 的客户自选保存卡流程。merchantCustId 的取值要求、保存支付方式结果通知与已保存 token 的查询、删除见保存支付方式。
创建固定计划的初始订阅
初始订阅支付使用 subProductType=SUBSCRIBE。服务端应维护允许购买的计划映射,并传入稳定、可读的字段 subscription.productName;计费方式由字段 subscription.selfExecute 决定。托管卡订阅可同时传入字段 subscription.bindCard =true,在订阅成功时保存客户卡,此时会收到两条独立通知。
托管订阅与自主管理订阅的选择、合约凭证、生命周期通知、续费与升降级、订阅并绑卡的双通知处理见订阅支付。
预授权
传入字段 txnType =AUTH(subProductType 保持 DIRECT)时,本次支付是预授权:冻结客户卡上的订单金额,不立即扣款;SDK 集成流程与普通支付一致。预授权成功后保存响应中的 transactionId 与 paymentId,后续请款或撤销由服务端调用预授权请款或撤销完成。
适用范围、请款与撤销的生命周期、通知、边界与状态判断见预授权与请款。
分账
分账是平台模式下的能力:平台商户以收款子商户的 merchantNo 创建支付,并传入字段 paymentMethodOptions 在其中的 share 设置 profitShare=true,该笔支付才可参与分账;SDK 集成流程与普通支付一致。同时设置 profitShareRate 时,SALE 或 CAPTURE 成功后由 Onerway 自动分账;不设置时由服务端通过 API 发起分账。需要接收自动分账及自动分账回退通知时,同时设置 profitShareNotifyUrl。paymentMethodOptions 按接口要求以 JSON 字符串提交。
自动分账与通过 API 发起分账的选择、结果通知、查询与分账回退见分账。