На странице
Low-Code SDK для JavaScript
Добавьте на страницу настраиваемую кнопку оплаты, выберите источник суммы и оформление и откройте Paymos без собственной формы.
Low-Code SDK позволяет встроить кнопку оплаты прямо на ваш сайт. При нажатии SDK определяет сумму, создаёт инвойс через публичный SDK-ключ (pk_...) и открывает форму оплаты — модальным окном в iframe или переходом на всю страницу.
Сниппет работает только в проекте, у которого способ подключения — Low-Code. Способ вы выбираете при создании проекта, и потом он не меняется; в проекте с любым другим способом POST /public/v1/sdk отвечает 403 embed_not_enabled.
Low-Code SDK — удобная обёртка над той же платёжной страницей, которую POST /v1/invoices возвращает в payment_url; в режиме iframe SDK открывает её с ?embed=true. Ручное перенаправление и ручное встраивание в iframe описаны на Платёжной странице.
SDK отправляет POST на https://paymos.io/public/v1/sdk — тот же origin, что отдаёт paymos-widget.js — и передаёт ключ в заголовке X-Sdk-Key.
Если сумма не определена, а вы передали pos_url, кнопка открывает Терминал по этому адресу — интерфейс с нампадом для ввода суммы вручную. Без pos_url клик без суммы завершается ошибкой и событием paymos:error.
Как это работает
- 01Добавьте скрипт SDK и элемент для монтирования на страницу
- 02Вызовите
PaymosWidget.mount()сapi_key,project_idи параметрами - 03Клиент нажимает кнопку
- 04SDK определяет сумму (фиксированная, функция обратного вызова или селектор поля ввода)
- 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— фиксированная десятичная строка в настройках. Подходит для страниц с одним товаром или фиксированной ценой. - 02
get_amount()— функция обратного вызова, возвращающая сумму десятичной строкой. Используйте, когда итог вычисляется динамически (например, из корзины). - 03
amount_selector— CSS-селектор, указывающий на элемент<input>. SDK читает его.valueв момент клика. Удобно, когда сумму вводит сам клиент.
Если ни один из источников не вернул корректную положительную десятичную строку, 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>
Оба режима обращаются к одному серверу, отправляют те же вебхуки и те же события в window. Разница только в том, кто отвечает за стили кнопки — на open() построена ссылка Открыть демо в дашборде (три независимо оформленные кнопки на одном общем оверлее).
Когда использовать SDK, а когда REST API
Low-Code SDK — браузерный инструмент. Он ставит кнопку оплаты на статическую HTML-страницу, без серверной части. Подходит для:
- пожертвований и чаевых (сумму выбирает клиент)
- касс и точек продаж (сумму вводит сотрудник)
- виджетов с произвольной суммой («заплатите сколько хотите»)
- демонстраций в тестовой и промежуточной среде
Для случаев, где цена фиксирована на вашей стороне (подписки, цифровые товары, физические заказы, курсы, лицензии), сумма в примере ниже редактируется из инструментов разработчика в браузере — клиент может отправить 0.01 за тариф 99 $. В таких случаях создавайте инвойс через REST API на сервере, секретным ключом. SDK тут ни при чём: так устроена любая оплата, начинающаяся в браузере (Stripe, LemonSqueezy, PayPal) — публичный ключ на странице, секретный на сервере.
Параметры
| Параметр | Тип | Обязателен | Описание |
|---|---|---|---|
api_key |
string |
Да | Публичный SDK-ключ из дашборда (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/Терминала. Если задан, кнопка открывает Терминал, когда сумма не определилась |
target |
string |
Нет | "_self" (по умолчанию) или "_blank" (только при переходе на всю страницу) |
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 отправляет события 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, поэтому посторонние скрипты на странице мерчанта подделать их не могут.
При переходе на всю страницу браузер уходит с сайта до получения результата — подтверждение берите из вебхука на сервере.
// 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 сверяет Origin страницы с полем Разрешённый origin в настройках виджета. Не совпал — запрос отклоняется до того, как появится инвойс.
Значение одно, не список, и по умолчанию оно пустое. Пустое поле означает «отовсюду»: пока вы его не заполнили, кнопку с вашим публичным ключом pk_... можно встроить на любой чужой странице. Заполните его до выхода в рабочую среду. Запросы с того же домена, откуда отдаётся сама платёжная страница — например, экран терминала, — проверку пропускают всегда.
Режим Терминала
Режим включается параметром pos_url — укажите в нём адрес страницы Терминала. Тогда, если сумма не определена (нет amount, get_amount() вернул null, поле по amount_selector пусто), SDK откроет этот адрес — нампад для ввода суммы вручную. Подходит для точек продаж, где сумма меняется от транзакции к транзакции.
Без pos_url тот же случай завершается ошибкой PaymosWidget requires an amount, amountSelector, or price_id. — она приходит на страницу событием paymos:error.