本页内容
JavaScript Low-Code SDK
给任何网页添加可配置的支付按钮,自选金额来源和主题,无需搭建后端表单即可打开 Paymos 收银台。
Low-Code SDK 让你把支付按钮直接嵌入网站。客户点击时,SDK 解析付款金额,用你的公开 SDK key(pk_...)创建账单,并打开收银台表单——iframe 弹窗或整页重定向。
Low-Code SDK 是 POST /v1/invoices 以 payment_url 返回的那个托管收银台页面的便捷封装;iframe 模式下它以 ?embed=true 打开该收银台。原始重定向和手动 iframe 契约见 托管收银台。
底层上,SDK 向 https://paymos.io/public/v1/sdk 发 POST——与提供 paymos-widget.js 的同一来源——你的 key 放在 X-Sdk-Key 请求头。
如果没有可用金额且你传了 pos_url,按钮改为打开 Terminal 页面——一个手动输入金额的数字键盘。没有 pos_url 时,无金额可解析的点击会抛错并发出 paymos:error。
工作流程
- 01在页面中加入 SDK 脚本和挂载点
- 02调用
PaymosWidget.mount(),传入api_key、project_id和选项 - 03客户点击按钮
- 04SDK 解析金额(静态值、回调或输入框选择器)
- 05有金额——SDK 创建账单并打开收银台
- 06无金额且设了
pos_url——SDK 打开该 URL 的 Terminal 数字键盘 - 07无金额且无
pos_url——SDK 抛错并发出paymos:error - 08付款被处理——webhook 发送到你注册的 webhook URL
安装
<script src="https://paymos.io/v1/paymos-widget.js"></script>
<div id="paymos-widget"></div>
解析金额
SDK 在按钮被点击的那一刻解析付款金额,按以下顺序取第一个可用来源:
- 01
amount——配置中传入的固定十进制字符串。适合单商品页或固定价格条目。 - 02
get_amount()——返回十进制字符串金额的回调函数。总额动态计算(如购物车)时使用。 - 03
amount_selector——指向<input>元素的 CSS 选择器。SDK 在点击时读取它的.value。适合客户自己输入金额的场景。
如果以上都返回不了有效的正数十进制字符串,SDK 打开你 pos_url 指向的 Terminal——一个手动输入金额的数字键盘。如果没设 pos_url,该点击抛出 PaymosWidget requires an amount, amountSelector, or price_id.,收银台不会打开。
// Fixed price (price_id) — RECOMMENDED for fixed products.
// Create the price once in the dashboard; the server resolves the amount and
// currency from it, so a buyer cannot change them in DevTools. No amount in the embed.
PaymosWidget.mount('#paymos-widget', {
api_key: 'YOUR_PUBLIC_KEY',
price_id: 'price_YOUR_PRICE_ID'
});
// Fixed amount — client-supplied (editable in the browser; use for donations / free-amount)
PaymosWidget.mount('#paymos-widget', {
api_key: 'YOUR_PUBLIC_KEY',
project_id: 'prj_YOUR_PROJECT_ID',
amount: '25.00',
currency: 'USD'
});
// Dynamic amount — computed at click time
PaymosWidget.mount('#paymos-widget', {
api_key: 'YOUR_PUBLIC_KEY',
project_id: 'prj_YOUR_PROJECT_ID',
get_amount: () => calculateCartTotal().toFixed(2),
currency: 'USD'
});
// Input selector — reads value from an <input> element
PaymosWidget.mount('#paymos-widget', {
api_key: 'YOUR_PUBLIC_KEY',
project_id: 'prj_YOUR_PROJECT_ID',
amount_selector: '#donation-amount',
currency: 'USD'
});
两种集成模式
SDK 暴露两个入口。按页面需要任选其一:
mount(selector, opts)——SDK 渲染按钮
SDK 把一个完整样式、开箱即用的支付按钮注入目标元素(文字来自 label 选项,默认 "Support with crypto")。适合单商品页、简单落地页、捐赠挂件——任何你不想写 CSS 的地方。
<script src="https://paymos.io/v1/paymos-widget.js"></script>
<div id="paymos-widget"></div>
<script>
PaymosWidget.mount('#paymos-widget', {
api_key: 'pk_live_…',
project_id: 'prj_…',
amount: '25.00',
currency: 'USD',
label: 'Support with crypto'
});
</script>
open(opts)——你渲染按钮,SDK 打开浮层
你完全掌控按钮 DOM(你的设计系统、你的 CSS、你的图标),在点击处理器里调用 PaymosWidget.open(opts)。适合多套餐定价页、购物车、自定义 UI 框架(React、Vue、Svelte 组件)。
<button id="buy-growth">Subscribe to Growth — $79/mo</button>
<script>
document.getElementById('buy-growth').addEventListener('click', function () {
PaymosWidget.open({
api_key: 'pk_live_…',
project_id: 'prj_…',
amount: 79,
currency: 'USD',
client_id: 'plan:growth'
});
});
</script>
两种模式打同一个后端、发同样的 webhook、发同样的 window 事件。区别纯粹在按钮样式由谁负责——open() 也是控制台打开演示链接启动的方式(一个带三个独立样式按钮的定价页,全部走同一个共享浮层)。
何时用 SDK,何时用 REST API
Low-Code SDK 是浏览器侧工具——在没有后端的静态 HTML 页面上放一个支付按钮。因此它非常适合:
- 捐赠 / 打赏(客户自选金额)
- POS / 收银台流程(店员输入金额)
- 自由金额挂件("你来定价")
- 内部沙箱 / 预发布演示
凡是价格由你侧固定的场景(订阅、数字商品、实体订单、课程、许可证),记住金额就在页面里、可以从 DevTools 改——有决心的客户可以给你的 $99 套餐提交 0.01。改用你服务器上的 REST API 配 secret key。SDK 没有缺陷;这是所有客户端收银台(Stripe、LemonSqueezy、PayPal)共有的标准分工:页面上放公开 key,服务器上放 secret key。
配置
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
api_key |
string |
是 | 控制台中的公开 SDK key(pk_...) |
project_id |
string |
是,除非提供 price_id |
项目标识(prj_...) |
price_id |
string |
否 | 控制台中创建的固定价格(price_...)。服务器从中解析金额和币种,买家无法修改——固定价格商品推荐用它。优先于下面所有金额来源 |
amount |
string | number |
否 | 固定付款金额,十进制字符串或数字 |
get_amount |
function |
否 | 点击时返回十进制字符串金额的回调 |
amount_selector |
string |
否 | 含金额的输入框的 CSS 选择器 |
currency |
string |
否 | 法币代码(USD、EUR 等)。默认:USD |
client_id |
string |
否 | 你的内部客户 ID(附在账单上) |
mode |
string |
否 | "iframe"(默认)——弹窗浮层。"redirect"——整页跳转 |
label |
string |
否 | 按钮文字。默认:"Support with crypto" |
width |
string |
否 | "auto"(默认)或 "full"(100% 宽度) |
accent_color |
string |
否 | 按钮强调色(hex)。默认:#ff6b35 |
text_color |
string |
否 | 按钮文字颜色(hex)。默认:#ffffff。只有你同时传了自定义 accent_color 时才做对比度检查:你的颜色对它达到 4.5 就保留,否则 SDK 按实测对比度改用黑色或白色。用出厂强调色时不做检查,你给的值原样生效 |
radius |
number |
否 | 按钮圆角,0-32 px。默认:18 |
frame_title |
string |
否 | iframe 元素的无障碍标题。默认:"Paymos checkout" |
aria_label |
string |
否 | 弹窗对话框的无障碍名称。默认:"Paymos checkout" |
pos_url |
string |
否 | 你的 POS/Terminal 页面 URL。设置后,无金额可解析时按钮打开 Terminal |
target |
string |
否 | "_self"(默认)或 "_blank"(仅 redirect 模式) |
auto_close_delay |
number |
否 | 成功页在弹窗自动关闭前保持显示的毫秒数。默认:0(禁用)。弹窗内任何用户交互都会取消它 |
haptics |
boolean |
否 | 在支持的平台上启用短震动反馈(Android、部分 PWA)。iOS Safari 忽略 Vibration API——那里为空操作。遵循 prefers-reduced-motion。默认:true |
timeout |
number |
否 | 账单创建请求中止前的毫秒数。必须为正数;其他值回退到默认值。默认:30000 |
debug |
boolean |
否 | 向控制台输出完整 Error 对象而非仅消息。默认:false |
完整示例
<script src="https://paymos.io/v1/paymos-widget.js"></script>
<div id="paymos-widget"></div>
<script>
PaymosWidget.mount('#paymos-widget', {
api_key: 'YOUR_PUBLIC_KEY',
project_id: 'prj_YOUR_PROJECT_ID',
amount: '25.00',
currency: 'USD',
label: 'Support with crypto',
mode: 'iframe',
accent_color: '#FF6B35',
text_color: '#FFFFFF',
radius: 20
});
</script>
编程式 API
也可以不挂载按钮直接打开收银台:
// Open checkout programmatically (no button)
await PaymosWidget.open({
api_key: 'YOUR_PUBLIC_KEY',
project_id: 'prj_YOUR_PROJECT_ID',
amount: '50.00',
currency: 'USD',
mode: 'iframe'
});
// Close the modal
PaymosWidget.close();
// Remove the button and clean up
PaymosWidget.destroy('#paymos-widget');
事件
SDK 在 window 上派发 CustomEvent,让你的页面响应收银台生命周期。所有负载在 event.detail 上。
| 事件 | 触发时机 | event.detail |
|---|---|---|
paymos:opened |
弹窗已挂载且 iframe URL 已设置 | { url } |
paymos:closed |
弹窗被移除(任何原因,包括可选的 auto_close_delay 计时器触发) |
{ reason: 'escape' | 'iframe' | 'replaced' | 'api' | 'success' } |
paymos:succeeded |
客户付款达到 paid 或 paid_over。由 iframe 内通过 postMessage 发出 |
{ invoiceId } |
paymos:failed |
终态失败(underpaid、expired、cancelled) |
{ invoiceId, reason } |
paymos:error |
SDK 连账单都没能创建(网络/认证/CORS/超时) | { message } |
succeeded / failed 事件只在收银台以 iframe 模式打开时触发——由付款页调用 window.parent.postMessage 投递。SDK 只接受来自它所嵌入收银台 URL 来源、且来自该 iframe 自身 contentWindow 的消息,因此商户页面上的任何第三方都无法伪造它们。
redirect 模式的收银台在结果已知前页面已跳走,因此用你服务器上的 webhook 确认结算。
// 1. The customer paid — auto-close the modal and redirect to a thank-you page.
window.addEventListener('paymos:succeeded', (e) => {
console.log('Paid:', e.detail.invoiceId);
PaymosWidget.close();
// Absolute and on your own domain: a root-relative path in a published
// code sample gets crawled as one of OUR URLs — Googlebot did exactly that
// and filed /thank-you?order= as a 404 against paymos.io.
window.location.href = 'https://your-shop.example/thank-you?order=' + e.detail.invoiceId;
});
// 2. Payment failed (underpaid / expired / cancelled).
window.addEventListener('paymos:failed', (e) => {
console.warn('Payment failed:', e.detail.invoiceId, e.detail.reason);
// e.detail.reason: 'underpaid' | 'expired' | 'cancelled'
});
// 3. Modal lifecycle.
window.addEventListener('paymos:opened', (e) => console.log('Opened', e.detail.url));
window.addEventListener('paymos:closed', (e) => console.log('Closed', e.detail.reason));
// e.detail.reason: 'escape' | 'iframe' | 'replaced' | 'api' | 'success'
// 4. Invoice creation failed (network down, bad config, server error).
window.addEventListener('paymos:error', (e) => {
console.error('SDK error:', e.detail.message);
});
允许的来源
SDK 只在与你挂件设置中配置的允许的来源匹配的域名上工作。来自其他来源的请求会被拒绝。
Terminal 回退
回退是可选的:把 pos_url 指向你的 Terminal 页面。当解析不到有效金额(没有 amount、get_amount() 返回 null,或 amount_selector 输入框为空)时,SDK 打开该 URL——一个手动输入金额的数字键盘。适合每笔交易金额都不同的销售点场景。
不设 pos_url 时,同样的情况改为抛出 PaymosWidget requires an amount, amountSelector, or price_id.,以 paymos:error 事件到达你的页面。