Clink JavaScript SDK 用于在浏览器应用中拉起 Clink Checkout,支持整页跳转和嵌入式 checkout 两种模式,并通过 publishable key 初始化。
安全提示: 浏览器端请使用 publishable key。不要在客户端暴露 Secret API keys。
NPM Package
在 npmjs.com 查看该包
Create Checkout Session
先在你的后端创建 checkout session,再拉起 checkout。
Checkout Session Guide
了解 hosted checkout 的完整工作流程。
使用你偏好的包管理器从 npm 安装:
npm install @clink-ai/clink-js
如果你需要浏览器全局版本,该包也提供了 UMD bundle。你可以自托管 dist/index.umd.js,加载后通过 window 上的 Clink.loadClink(...) 使用。
初始化
使用 publishable key 初始化 SDK:
import { loadClink } from '@clink-ai/clink-js';
const clink = await loadClink('pk_uat_xxxxxxxxx', {
checkoutEnvironment: 'uat',
locale: 'en-US',
});
支持的 publishable key 格式包括 pk_test_*、pk_uat_* 和 pk_prod_*。
如果你已经明确知道最终 checkout host,也可以直接传入 checkoutBaseUrl 跳过 bootstrap:
import { loadClink } from '@clink-ai/clink-js';
const clink = await loadClink('pk_prod_xxxxxxxxx', {
checkoutBaseUrl: 'https://checkout.clinkbill.com',
});
初始化参数
checkoutEnvironment:uat 或 live。未传 checkoutBaseUrl 时会使用它
checkoutBaseUrl:直接指定 checkout host。传入后会跳过 bootstrap
locale:会透传给 bootstrap 请求
origin:覆盖当前站点 origin
fetchImpl:为非浏览器运行环境提供自定义 fetch
Redirect Checkout
如果你希望由 Clink 接管整页支付流程,可以使用 redirect 模式。
import { loadClink } from '@clink-ai/clink-js';
const clink = await loadClink('pk_uat_xxxxxxxxx', {
checkoutEnvironment: 'uat',
});
document
.getElementById('checkout-button')
?.addEventListener('click', async () => {
await clink.redirectToCheckout({
// 当后端返回 opaque session token 时,优先使用 sessionParam
sessionParam: 'sess_xxx#token_xxx',
replace: false,
});
});
redirectToCheckout 支持以下参数:
sessionParam:优先使用
sessionId:只有 session ID 时可用
replace:使用 window.location.replace(...) 而不是 assign(...)
如果同时传入 sessionParam 和 sessionId,会优先使用 sessionParam。
Embedded Checkout
如果你希望支付流程停留在当前页面中,可以使用嵌入式 checkout。
import { loadClink } from '@clink-ai/clink-js';
const clink = await loadClink('pk_uat_xxxxxxxxx', {
checkoutEnvironment: 'uat',
});
const embedded = await clink.initEmbeddedCheckout({
async fetchSession() {
const response = await fetch('/api/clink/checkout-session', {
method: 'POST',
});
return await response.json();
// {
// sessionId: 'sess_xxx',
// checkoutUrl: 'https://checkout.clinkbill.com/pay/sess_xxx%23token_xxx',
// orderId: 'ord_xxx'
// }
},
onEvent(event) {
console.log(event.type, event.payload);
},
async pollStatus({ sessionId, orderId, attempt }) {
const response = await fetch(
`/api/clink/checkout-status?sessionId=${sessionId}`,
);
const result = await response.json();
if (result.state === 'pending' || result.state === 'payment') {
return null;
}
return {
state: result.state,
payload: {
orderId,
attempt,
},
};
},
});
embedded.mount('#clink-checkout');
fetchSession 必须在你的后端创建 checkout session,并返回最终的 checkout URL。SDK 会原样挂载这个 URL,不会改写其中的 query 参数。
嵌入式参数
fetchSession:必填。必须返回 { sessionId, checkoutUrl, orderId? }
onEvent:接收 checkout 生命周期事件
autoResize:自动处理 iframe 高度变化。默认:true
autoDestroyOnComplete:支付成功后自动销毁实例。默认:true
pollStatus:可选的轮询函数,用于判断终态
pollIntervalMs:轮询间隔,单位毫秒。默认:2000
嵌入式实例 API
mount(container):挂载到 CSS selector 或 HTMLElement
unmount():移除 iframe,但保留实例可复用
destroy():彻底销毁实例
on(type, handler):订阅指定事件
getState():返回 { mounted, destroyed }
事件与状态
嵌入式 checkout 会触发以下事件:
| Event | Description |
|---|
ready | checkout iframe 已就绪或已完成加载 |
resize | iframe 请求更新高度 |
state_change | checkout 状态发生变化 |
complete | 到达终态 |
hosted_return | hosted checkout 将控制权返回父页面 |
error | SDK 或轮询过程出现错误 |
可用的嵌入式状态包括:
payment
pending
success
cancelled
error
expired
错误处理
当参数校验、bootstrap 或嵌入式 checkout 初始化失败时,SDK 会抛出 ClinkError。
import {
CLINK_ERROR_CODES,
ClinkError,
loadClink,
} from '@clink-ai/clink-js';
try {
const clink = await loadClink('pk_uat_xxxxxxxxx', {
checkoutEnvironment: 'uat',
});
await clink.redirectToCheckout({
sessionId: 'sess_xxx',
});
} catch (error) {
if (error instanceof ClinkError) {
if (error.code === CLINK_ERROR_CODES.INVALID_PUBLIC_KEY) {
console.error('Invalid publishable key');
}
}
}
常见错误码包括:
INVALID_PUBLIC_KEY
INVALID_CHECKOUT_ENV
BOOTSTRAP_REQUEST_FAILED
INVALID_REDIRECT_PARAMS
INVALID_EMBEDDED_OPTIONS
SESSION_ID_FETCH_FAILED
EMBEDDED_CHECKOUT_DISABLED
CONTAINER_NOT_FOUND
参考资料