На странице
JavaScript Widget SDK
Добавьте на страницу настраиваемую кнопку оплаты, выберите источник суммы и оформление и откройте Paymos без собственной формы.
Widget SDK позволяет встроить кнопку оплаты прямо на ваш сайт. При нажатии SDK определяет сумму, создаёт инвойс через публичный SDK-ключ (pk_...) и открывает форму оплаты — как iframe-модалку или через полностраничный редирект.
Widget SDK — удобная обёртка над той же hosted checkout страницей, которую даёт payment_url; в iframe-режиме SDK открывает checkout с ?embed=true. См. Платёжную страницу для raw redirect и manual iframe-контракта.
SDK отправляет POST на https://paymos.io/public/v1/sdk — тот же origin, что отдаёт paymos-widget.js — и передаёт ключ в заголовке X-Sdk-Key. Если вы self-host, переопределите endpoint через параметр api_url.
Если сумма не определена, а вы передали pos_url, кнопка открывает Терминал по этому адресу — интерфейс с нампадом для ввода суммы вручную. Без pos_url клик без суммы завершается ошибкой и событием paymos:error.
Как это работает
- 01Добавьте скрипт SDK и элемент для монтирования на страницу
- 02Вызовите
PaymosWidget.mount()сapi_key,project_idи параметрами - 03Клиент нажимает кнопку
- 04SDK определяет сумму (фиксированная, callback или селектор инпута)
- 05Если сумма есть — SDK создаёт инвойс и открывает чекаут
- 06Если суммы нет, но задан
pos_url— SDK открывает Терминал с нампадом по этому адресу - 07Если суммы нет и
pos_urlне задан — SDK выбрасывает ошибку и шлёт событиеpaymos:error - 08Оплата обрабатывается — вебхук отправляется на зарегистрированный URL вебхука
Установка
<script src="https://paymos.io/v1/paymos-widget.js"></script>
<div id="paymos-widget"></div>
Определение суммы
SDK определяет сумму в момент нажатия на кнопку, используя первый доступный источник:
- 01
amount— фиксированная decimal-строка в конфиге. Подходит для страниц с одним товаром или фиксированной ценой. - 02
get_amount()— функция обратного вызова, возвращающая сумму как decimal-строку. Используйте, когда итог вычисляется динамически (например, из корзины). - 03
amount_selector— CSS-селектор, указывающий на элемент<input>. SDK читает его.valueв момент клика. Удобно, когда сумму вводит сам клиент.
Если ни один из источников не вернул валидную положительную decimal-строку, SDK открывает Терминал по адресу из pos_url — нампад для ручного ввода суммы. Если 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 открывает оверлей
Вы полностью владеете разметкой кнопки (ваша дизайн-система, ваш 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>
Оба режима стучат в один backend, шлют те же webhooks и эмитят те же window events. Разница только в том, кто отвечает за стили кнопки — на open() построена ссылка Открыть демо в дашборде (прайсинг с тремя независимо стилизованными кнопками через один общий оверлей).
Когда использовать SDK, а когда REST API
Widget SDK — браузерный инструмент. Он ставит Pay-кнопку на статическую HTML-страницу без backend. Подходит для:
- Донатов / tip jar (клиент сам выбирает сумму)
- POS / кассирского ввода (сумму вводит сотрудник)
- Free-amount виджетов («заплати сколько хочешь»)
- демонстраций в тестовой и промежуточной среде
Для случаев, где цена фиксирована на вашей стороне (подписки, цифровые товары, физические заказы, курсы, лицензии), сумма в сниппете ниже редактируется из DevTools — клиент может отправить 0.01 за тариф 99 $. В таких случаях создавайте инвойс через REST API на сервере с secret key. SDK не сломан, это стандартное разделение для любого client-side checkout (Stripe, LemonSqueezy, PayPal): publishable key на странице, secret key на сервере.
Параметры
| Параметр | Тип | Обязателен | Описание |
|---|---|---|---|
api_key |
string |
Да | Публичный SDK-ключ из дашборда (pk_...) |
project_id |
string |
Да, если не передан price_id |
Идентификатор проекта (prj_...) |
price_id |
string |
Нет | Фиксированная цена, созданная в дашборде (price_...). Сумму и валюту сервер берёт из неё, покупатель их не изменит — рекомендуемый вариант для товаров с фиксированной ценой. Имеет приоритет над всеми источниками суммы ниже |
amount |
string | number |
Нет | Фиксированная сумма оплаты — decimal-строка или число |
get_amount |
function |
Нет | Функция обратного вызова, возвращающая сумму как decimal-строку в момент клика |
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 ниже WCAG AA (4,5) — SDK возьмёт чёрный или белый, смотря что контрастнее |
radius |
number |
Нет | Скругление кнопки, 0-32 px. По умолчанию: 18 |
frame_title |
string |
Нет | Доступное название для iframe-элемента. По умолчанию: "Paymos checkout" |
aria_label |
string |
Нет | Доступное название модального окна. По умолчанию: "Paymos checkout" |
pos_url |
string |
Нет | Адрес вашей страницы POS/Терминала. Если задан, кнопка открывает Терминал, когда сумма не определилась |
target |
string |
Нет | "_self" (по умолчанию) или "_blank" (только для redirect) |
api_url |
string |
Нет | Переопределить endpoint. По умолчанию — origin, отдающий paymos-widget.js (например https://paymos.io/public/v1/sdk). Используйте только для self-host или локальной разработки. |
auto_close_delay |
number |
Нет | Миллисекунды, в течение которых экран успешной оплаты остаётся видимым перед автоматическим закрытием модала. По умолчанию: 0 (выключено). Отменяется любым взаимодействием пользователя внутри модала. |
haptics |
boolean |
Нет | Включить короткую тактильную отдачу на поддерживающих платформах (Android, некоторые PWA). iOS Safari игнорирует Vibration API — там no-op. Уважает 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 диспатчит CustomEvent-ы на window, чтобы страница могла реагировать на жизненный цикл чекаута. Все полезные данные лежат в event.detail.
| Событие | Когда срабатывает | event.detail |
|---|---|---|
paymos:opened |
Модал смонтирован, URL для iframe установлен. | { 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 принимает сообщение только с origin той страницы чекаута, которую сам встроил, и только из её 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();
window.location.href = '/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 работает только на доменах, совпадающих с Allowed Origin в настройках виджета. Запросы с других доменов отклоняются.
Режим Терминала
Режим включается параметром pos_url — укажите в нём адрес страницы Терминала. Тогда, если сумма не определена (нет amount, get_amount() вернул null, инпут по amount_selector пуст), SDK откроет этот адрес — нампад для ввода суммы вручную. Подходит для точек продаж, где сумма меняется от транзакции к транзакции.
Без pos_url тот же случай завершается ошибкой PaymosWidget requires an amount, amountSelector, or price_id. — она приходит на страницу событием paymos:error.