跳转到主要内容
Elements 把 Clink 管理的支付输入、钱包按钮、3DS、二维码和第三方支付交互,嵌进商户自己的页面里。订单摘要、页面结构、支付按钮和状态提示则完全由商户控制。 想最快收到钱就用 Hosted Checkout。需要自己定义订单摘要、页面结构和交互时,再用 Elements。
建议锁定 @clink-ai/clink-elements 的版本号。

完整链路长什么样

Elements 只替换前端那一段。创建 Session 仍然必须在商户服务端完成,因为那一步要用 Secret Key。 第 1 步要提交的是商品标识,不是浏览器算好的最终金额。金额由第 2 步在服务端重新算。

四方职责

一、服务端:写一个自己的 Session 接口

这一层不是可选优化。它同时是三条边界:Secret Key 的安全边界、金额校验的边界、本地订单关联的边界。 下面用的 clinkRequest 就是 Hosted Checkout 接入 里那个带认证头的 helper,它返回的是响应中的 data。
三个要点:
  • uiMode 传 elements,returnUrl 必填。URL 里可以放 {ELEMENTS_SESSION_ID},Clink 会替换成真实 Session ID
  • 字段名是 returnUrl。有些旧资料写成 redirectUrl,那是错的——redirectUrl 是 requires_action 场景下响应里的跳转地址
  • merchantReferenceId 只用于关联对账,不是幂等键。同一个值调两次会得到两个 Session
上面 clinkRequest 拿到的 data,节选如下:
Clink 的原始响应外面还包着 { "code": 200, "msg": "success", "data": { ... } } 这层信封,clinkRequest 已经剥掉了。
expireTime 当前返回的是 "2026-07-30 12:00:00" 这种格式,不带时区标识,也不是 RFC 3339。别直接丢给 new Date() 或按本地时间解析——不同运行环境的解释会不一致。也不要按”商户账户时区”或浏览器时区去推断。 后端目前用服务进程的默认时区序列化,没有按账户做转换,所以这个字符串代表哪个时区,接口本身没有表达。要精确处理跨时区逻辑,得等后端把输出契约升级成带 offset 的 RFC 3339 或 Unix 时间戳。在那之前,判断 Session 是否还能付款请看 status,不要拿这个字符串自己算。
这是节选,完整字段以 Create checkout session 为准。两件事要注意:
  • 响应里没有 Publishable Key,也没有 environment。 这两样来自商户自己的应用配置,见下一节
  • 响应里有 url,那是托管收银台地址。Elements 接入不使用它
不要把 Clink 的原始响应整个转发给浏览器。包装接口只返回前端真正需要的字段,推荐就一个 sessionId。

二、前端:调自己的接口,然后初始化

浏览器只做两件事:向商户后端要一个 sessionId,然后用它初始化 SDK。
PUBLIC_CLINK_PUBLISHABLE_KEY 和 environment 是应用的部署配置,来自后台 开发者 > API Keys 里的 Publishable Key(pk_uat_ 开头)。它们可以公开出现在浏览器里,但不来自 Create Session 的响应。
SDK 的参数名是 publishKey,正文里说的 Publishable Key 就是它。代码里必须写 publishKey。

三、挂载、提交与第三方按钮

结账页上可能出现两类按钮,处理方式完全不同: 商户自己的支付按钮 —— 银行卡这类需要宿主触发提交的流程。点击后调 clink.submit()。 SDK 内置的第三方按钮 —— Apple Pay、Google Pay、PayPal 等。它们由 paymentMethod 组件内部渲染,点击也由 SDK 接管。这时 SDK 会发 submit-visible: false,宿主页面要把自己的按钮藏起来。
三件事别做:
  • 别按支付方式名称硬编码按钮显隐。 一切以 submit-visible 为准
  • 别在自己的页面里再画一套 Apple Pay、Google Pay 或 PayPal 按钮。 那些由 SDK 渲染,自行绘制的那套点了没用
  • 别对第三方按钮调 clink.submit()。 它们的点击由 SDK 处理
另外,第三方方式会不会出现,取决于商户配置、Session、币种、浏览器和设备能力。不要在页面上承诺每次都有。
submit-enabled 报告的是「能不能提交」。按钮写 disabled = !enabled,别把事件值直接塞进 disabled——那样逻辑正好反过来。

配置 SDK 按钮样式

从 0.0.3 开始,可以通过 presetOptions.sdkButtons 配置 Apple Pay、Google Pay、Link 和 PayPal 的按钮样式。
完整配置类型如下:
  • 为兼容当前所有按钮渲染方式,请将高度设置在 40–55 像素之间
  • 非有限值或小于等于 0 的高度会回退到 45;其他不受支持的正数不会回退,可能导致对应按钮初始化失败
  • 非有限值或负数圆角会回退到 6;超过按钮高度一半时会自动取高度的一半
  • 不受支持的主题和类型会回退到对应默认值
  • 所有 SDK 按钮都是 100% 宽度
  • Apple Pay 没有设置主题时,浅色模式用 black,深色模式用 white
  • PayPal 的高度和圆角由 Clink 应用在 PayPal 组件的外层容器上,不会作为 PayPal SDK 参数传入
按钮设置只在初始化时读取。如果设置发生变化,需要销毁当前实例后重新调用 loadClinkElements()。

获取 SDK 按钮可用状态

在挂载 paymentMethod 之前监听 sdk-button-initialized,避免漏掉首次事件。
返回值类型如下:
  • true 表示按钮初始化成功,并且当前设备可以使用
  • false 表示设备不支持、配置有误、网关不支持、第三方 SDK 加载失败,或按钮在当前初始化周期内超过 10 秒仍未完成
  • 只返回当前 Session 中存在的按钮;没有第三方按钮时返回 {}
每个按钮的当前 loading 周期都有 10 秒超时。当前轮次的全部第三方按钮成功、失败或超时后,事件才会触发。按钮重新进入 loading,或可用支付方式发生变化时,会开始新的等待周期;新周期结束后事件会再次触发,即使结果和上一次相同。

监听第三方支付弹窗

监听 sdk-dialog-open 和 sdk-dialog-close,即可获知第三方支付弹窗打开和关闭。回调参数是触发事件的支付方式。
回调值为 applePay、googlePay、link 或 paypal 之一。

配置货币选择器样式

从 0.0.5 开始,可以通过 presetOptions.currencySelect 自定义货币选择器的外观。所有样式参数都是标准的 CSS 样式对象,写法和 React 的 style 相同。
有多种货币时,各参数控制的区域如下([US]、[EU] 表示国旗图标):
  • oneCurrencyStyle 会完全替换默认样式,设置后需要自己指定字号、字重、颜色等
  • switcher 下的样式只覆盖你设置的属性,未设置的属性保持默认外观
  • 选中卡片会在 itemStyle、textStyle 的基础上叠加 selectedItemStyle、selectedTextStyle,同名属性以选中样式为准
  • 在 itemStyle 中设置边框色或背景色、在 textStyle 中设置文字颜色或字重后,默认的选中高亮会被覆盖,请同时设置对应的选中样式
  • hideIfOneCurrency 为 true 且只有 1 种货币时,oneCurrencyStyle 不生效
  • 标题、国旗图标和汇率说明暂不支持自定义
如果只需要修改当前选中卡片的边框,在 selectedItemStyle 中写需要变化的属性即可,其余属性沿用 itemStyle:
样式只在初始化时读取。如果需要修改,需要销毁当前实例后重新调用 loadClinkElements()。

使用 Express Checkout 快捷支付

从 0.1.0 开始,paymentMethod 支持 Express Checkout 模式。这个模式只展示 Apple Pay、Google Pay、PayPal 和 Link 快捷支付按钮。 Express Checkout 不是新的组件类型。创建 paymentMethod 时传入第二个参数即可开启:
不传第二个参数时,paymentMethod 仍是普通支付模式,行为与之前相同。

两种模式的区别

presetOptions 里的 locale、theme、primaryColor、radius 等通用配置在 Express Checkout 中照常生效。currencySelect 也可以照常创建和挂载。

配置项

完整类型如下:
  • 高度和圆角只能统一设置,不支持给单个按钮单独设置
  • 按钮文案只能通过 buttonType 选择第三方 SDK 支持的值
  • 按钮纵向排列,间距 8px,宽度占满容器

按钮排序与显示

设置了 paymentMethodOrder 时:
  1. 先按配置的顺序排列(不区分大小写,重复项和不支持的值会被忽略)
  2. Session 返回了、但配置里没写的方式,按 Session 原顺序追加到末尾
例如 Session 返回 paypal、applePay、googlePay,配置为 ['googlePay'],最终顺序是 googlePay、paypal、applePay。 一个按钮最终是否显示,要同时满足三个条件:
  • Session 返回了这种支付方式(取决于商户配置、币种等)
  • 对应的 visible 不是 'never'
  • 当前浏览器和设备支持,第三方 SDK 初始化成功
配置里写了某个按钮,不代表它一定会出现。可以监听 sdk-button-initialized(见上文「获取 SDK 按钮可用状态」)获知实际可用的按钮。
Session 里没有任何快捷支付方式时,组件不渲染任何内容(包括地址字段),并在控制台输出 warning。

账单地址与税费

如果 Session 需要计算税费,组件会在按钮上方展示国家、地址、城市、邮编等必要的地址字段。客户修改地址后,Clink 会自动重新计算税费并更新金额,这段时间内按钮暂时不可点击。 金额变化同样通过 amount-change 事件通知宿主页面,订单摘要以事件返回的金额为准。

事件

Express Checkout 复用现有事件,不需要额外监听新的事件: submit-enabled 和 submit-visible 针对宿主支付按钮,Express Checkout 中不需要处理。

使用限制

  • mode 在创建时确定,之后不能切换。需要换模式时,销毁当前实例并重新调用 loadClinkElements()
  • 同一个实例只能创建一个 paymentMethod,因此一个实例不能同时提供普通支付表单和 Express 按钮
  • 和普通模式一样,session-success 不是付款凭证,最终状态以后端收到的 Webhook 为准

四、事件

按用途分两组。 更新宿主 UI 流程提示
session-success 不是付款凭证,returnUrl 也不是。浏览器里的事件可以被伪造。正确做法是:收到 session-success 后跳到商户自己的结果页,结果页查询商户后端的订单状态。发货、充值、开通权益只能由后端根据验签后的 Webhook 和服务端查询结果决定。验签、去重和订单匹配见 Hosted Checkout 接入。

五、优惠码

可选能力。服务端的 Coupon 和 Promotion Code 怎么建,见 优惠与促销码。这里只讲前端。
回调参数是 { amount },金额字段在 amount 里面。写成 (info) => info.enablePromotionCode 拿到的是 undefined,优惠码入口会一直不显示。 折扣和最终应付金额以 amount 返回的为准,不要自己算。

六、错误处理

0.0.5 会抛出三类东西,处理方式不一样。

初始化:loadClinkElements()

它不是只抛 ClinkApiError。至少有三条路径: 响应体不是合法 JSON 时,await res.json() 还会抛原生 SyntaxError。 所以 catch 参数要按 unknown 处理,并且一定要留兜底分支:
0.0.5 还导出了 SessionExpiredError、SessionCompleteError、SessionLoadError、SessionNotSupportedError、PromoCodeError。这几个类在当前版本的产物里只有类定义,没有任何抛出路径。不要按它们写 instanceof 分支,条件永远不成立。等后续版本真的用上了再说。
拿到初始化错误时,按这几样查——注意每一项各有各的判断依据,不要都往一个接口上归因:

初始化之后:部分错误是同步抛的

不是所有运行期问题都走事件。 下面这些是同步抛出的原生 Error,必须用 try/catch 接:

支付流程中的错误:走事件

真正跟支付流程有关的错误由收银台 iframe 发事件转发,不会被包装成异常类。

七、实现约束

这几条写错会直接导致接入失败,其余布局细节按自己的设计来就行。

上线自查

  • 浏览器 Network 和构建产物里没有 Secret Key,也没有 Webhook 签名密钥
  • 浏览器只调用商户自己的 Session 包装接口,没有直接调 Clink 的 Create Session
  • 后端不相信浏览器传来的最终金额,按商品或购物车重新计算
  • 本地订单、merchantReferenceId 和 sessionId 三者的映射已保存
  • Publishable Key 和 environment 来自应用公开配置,没有被当成 Create Session 的响应字段
  • Apple Pay、Google Pay、PayPal 等按钮出现时,submit-visible 能让宿主页面的按钮隐藏
  • 使用 Express Checkout 时,页面没有放宿主支付按钮,并处理了没有可用按钮的情况
  • session-success 不直接触发发货,最终状态来自验签 Webhook 和后端查询
  • Session 变化或页面卸载时销毁了旧实例

接下来

Hosted Checkout 接入

后端和 Webhook 那两块,Elements 和 Hosted Checkout 完全一样。

上线检查

切生产前要过的清单。