Виджет оплаты Яндекс Пэй

Виджет оплаты — виджет в корзине заказа, который показывает доступные способы оплаты и позволяет покупателю запустить оплату заказа через Яндекс Пэй.

Виджет оплаты

Для подключения виджета вам понадобятся:

  • Merchant ID (merchantId) из личного кабинета Яндекс Пэй;
  • настроенная интеграция с Yandex Pay API;
  • платежная ссылка, которую ваш сервер получает при создании заказа;
  • HTML-контейнер для виджета.

Важно

Создавайте заказ и получайте платежную ссылку на сервере. Не передавайте секретный API-ключ в клиентский код и не считайте событие в браузере единственным подтверждением оплаты. Проверяйте итоговый статус заказа на сервере.

Шаг 1. Подключите SDK

Добавьте на страницу контейнер для виджета и подключите Web SDK перед закрывающим тегом </body>:

<div id="ya-pay-widget"></div>

<form id="submit-payment-form">
    <button type="submit">Оплатить</button>
</form>

<script
    id="ya-pay-sdk"
    data-yapay-sdk
    src="https://pay.yandex.ru/sdk/v1/pay.js"
    async
></script>

Важно

Используйте только адрес https://pay.yandex.ru/sdk/v1/pay.js.

Подпишитесь на загрузку SDK из JavaScript и дополнительно проверьте window.YaPay: к моменту выполнения вашего кода SDK уже может быть загружен.

const sdkScript = document.getElementById('ya-pay-sdk');

if (sdkScript instanceof HTMLScriptElement) {
    sdkScript.addEventListener('load', () => void onYaPayLoad());
    sdkScript.addEventListener('error', () => showAlternativePaymentMethod());
}

if (window.YaPay) {
    void onYaPayLoad();
}

Примечание

Сайт должен работать по HTTPS. Требования к CSP и другим заголовкам безопасности приведены в разделе Требования к подключению.

Шаг 2. Подготовьте данные платежа

Передайте в YaPay.createSession данные продавца:

const MERCHANT_ID = 'abcdef12-3456-7890-abcd-ef1234567890';

const cart = {
    items: [
        {
            productId: 'product-1',
            quantity: {
                count: '1',
            },
            total: '123.45',
        },
    ],
};

function createPaymentData(YaPay, cart) {
    return {
        env: YaPay.PaymentEnv.Sandbox,
        version: 4,
        currencyCode: YaPay.CurrencyCode.Rub,
        merchantId: MERCHANT_ID,
        totalAmount: '123.45',
        cart,
    };
}

Параметры платежа и их значения приведены в таблице:

Параметр Описание
env Среда выполнения. Для тестирования используйте YaPay.PaymentEnv.Sandbox, для приема реальных платежей — YaPay.PaymentEnv.Production.
version Версия платежного сценария. Для оплаты сервисом Яндекс Пэй укажите 4.
currencyCode Валюта заказа. Платежный виджет поддерживает YaPay.CurrencyCode.Rub.
merchantId UUID продавца, полученный при регистрации в Яндекс Пэй.
totalAmount Общая сумма заказа в виде строки. Значение вычисляется на стороне бэкенда. Используется как итоговая сумма заказа для расчетов виджета, даже если сумма позиций корзины отличается от totalAmount. Влияет на то, будет ли пользователю доступна оплата в Сплит.
cart Необязательные данные корзины.

Свойства объекта cart приведены в таблице:

Свойство Описание
cart.items Массив товаров в заказе. Если передан cart, массив должен содержать хотя бы один товар.
cart.items[].productId Идентификатор товара. Не должен быть пустым.
cart.items[].total Стоимость товара с учетом количества в виде строки. Значение не должно быть отрицательным. Сумма значений cart.items[].total не должна превышать totalAmount.
cart.items[].quantity Необязательные данные о количестве товара.
cart.items[].quantity.count Количество товара в виде строки. Если передано, значение должно быть больше нуля.

Важно

Не передавайте объект cart с пустым массивом items. Если корзина не нужна, не передавайте cart при создании сессии или удалите ее при обновлении с помощью cart: null.

Шаг 3. Создайте сессию и разместите виджет

Вызовите YaPay.createSession, затем разместите виджет в подготовленном контейнере с помощью mountWidget:

function onYaPayLoad() {
    const YaPay = window.YaPay;
    const paymentData = createPaymentData(YaPay, cart);

    YaPay.createSession(paymentData, {
        onUpdateError: (error) => {
            // Обновление не применено. Предыдущее состояние заказа сохранено.
            console.error(error);
            showCartUpdateError();
        },
    })
        .then((paymentSession) => {
            const widgetContainer = document.getElementById('ya-pay-widget');

            if (!widgetContainer) {
                throw new Error('Не найден контейнер платежного виджета');
            }

            paymentSession.mountWidget(widgetContainer, {
                widgetType: YaPay.WidgetType.PayWidget,
                widgetTheme: YaPay.WidgetTheme.Light,
                events: {
                    onPaymentFailed: () => {
                        // Оплата не прошла. Предложите повторить попытку
                        // или выбрать другой способ оплаты.
                        showPaymentError();
                    },
                    onFatalError: (error) => {
                        // Виджет не может продолжить работу.
                        // Покажите резервный способ оплаты.
                        console.error(error);
                        showAlternativePaymentMethod();
                    },
                },
            });

            configureCartUpdate(paymentSession);
            configurePaymentStart(paymentSession);
        })
        .catch((error) => {
            if (error.code === 'PAYMENT_SHEET_VALIDATION_ERROR') {
                // Исходные данные платежа не прошли проверку.
                showPaymentDataError(error);
                return;
            }

            // Не удалось создать платежную сессию или разместить виджет.
            console.error(error);
            showAlternativePaymentMethod();
        });
}

Метод YaPay.createSession возвращает Promise. Вызывайте mountWidget, update, startPayment и destroy у объекта платежной сессии, полученного после выполнения Promise. В рамках одной сессии можно разместить только один платежный виджет.

Параметры виджета

Параметры виджета и их значения приведены в таблице:

Параметр

Значение

Описание

Тема виджета

widgetTheme

YaPay.WidgetTheme.Light (по умолчанию)

Светлая тема

YaPay.WidgetTheme.Dark

Темная тема

Важно

Размер виджета определяется SDK при инициализации и может динамически меняться в процессе работы. Поэтому не задавайте контейнеру фиксированную высоту и не ограничивайте его с помощью max-height или overflow: hidden.

Предусмотрите в верстке адаптивный контейнер #ya-pay-widget: iframe занимает всю ширину контейнера, а SDK передает и обновляет его высоту при изменении содержимого виджета.

Шаг 4. Обновляйте виджет при изменении корзины

При изменении корзины передавайте ее актуальные значения в виджет:

function configureCartUpdate(paymentSession) {
    onCartChanged(() => {
        paymentSession.update(async () => {
            const {cart, totalAmount} = await updateCartOnMerchantServer();

            return { cart, totalAmount };
        });
    });
}

Метод paymentSession.update принимает функцию, которая возвращает актуальные данные платежа или Promise с ними. Виджет блокируется до завершения Promise, поэтому сначала обновите корзину на сервере, а затем верните ее актуальные значения.

При обновлении действуют следующие правила:

  • объект cart полностью заменяет текущую корзину;
  • значение cart: null удаляет корзину из состояния заказа;
  • если не передавать cart, текущая корзина сохраняется;
  • если не передавать totalAmount, текущая итоговая сумма сохраняется.

SDK проверяет итоговое состояние заказа до применения обновления. Если данные некорректны или Promise завершается с ошибкой, виджет сохраняет предыдущее состояние и вызывает onUpdateError. Метод paymentSession.update() при этом не возвращает результат.

Если вызвать paymentSession.update() несколько раз, SDK применит результат последнего вызова. Результаты и ошибки предыдущих незавершенных обновлений будут проигнорированы.

При удалении виджета вызовите paymentSession.unmountWidget(widgetContainer). Метод paymentSession.destroy() удаляет виджет и завершает всю сессию.

Шаг 5. Запустите оплату

При отправке формы создайте заказ на своем сервере. Передайте полученную платежную ссылку в paymentSession.startPayment:

function configurePaymentStart(paymentSession) {
    document.querySelector('#submit-payment-form').addEventListener('submit', async (event) => {
        event.preventDefault();

        try {
            // Сервер создает заказ через Yandex Pay API и возвращает ссылку
            // вида https://pay.ya.ru/l/1234.
            const paymentUrl = await createOrderOnMerchantServer();

            paymentSession.startPayment(paymentUrl);
        } catch (error) {
            console.error(error);
            showPaymentError();
        }
    });
}

Не формируйте paymentUrl в браузере. Ссылка возвращается Yandex Pay API после создания заказа на сервере продавца.

Обработка ошибок

Обрабатывайте ошибки в зависимости от этапа работы:

Этап Обработчик Действие
Загрузка Web SDK Событие error у тега script Покажите альтернативный способ оплаты. SDK еще не загружен и не может вызвать собственный обработчик.
Создание сессии catch у YaPay.createSession() Проверьте ошибку валидации с кодом PAYMENT_SHEET_VALIDATION_ERROR. Сессия с некорректными данными не создается.
Обновление заказа onUpdateError в параметрах YaPay.createSession() Сообщите об ошибке изменения заказа. Виджет продолжит работать с предыдущими корректными данными.
Работа размещенного виджета onFatalError в параметре events Покажите альтернативный способ оплаты, если виджет не может продолжить работу.
Оплата onPaymentFailed в параметре events Предложите повторить оплату или выбрать другой способ.

События виджета

Передайте обработчики событий в параметре events метода mountWidget.

Неустранимая ошибка — onFatalError

Обязательно задайте этот обработчик. Он вызывается, если уже размещенный виджет не может продолжить работу.

В этом случае предложите покупателю альтернативный способ оплаты:

const events = {
    onFatalError: (error) => {
        console.error(error);
        showAlternativePaymentMethod();
    },
};

Ошибка загрузки самого SDK происходит до создания виджета, поэтому обрабатывайте ее через событие error у скрипта.

Ошибка оплаты — onPaymentFailed

Вызывается, если платеж не удалось завершить.

Сообщите покупателю об ошибке и предложите повторить оплату или выбрать другой способ:

const events = {
    onPaymentFailed: () => {
        showPaymentError();
    },
};

Закрытие формы оплаты — onClose

В большинстве случаев обрабатывать это событие не требуется. Используйте его, если после закрытия формы оплаты нужно обновить интерфейс страницы — например, вернуть элементы управления в исходное состояние. paymentStatus принимает значение SUCCESS, ERROR или CANCELLED:

const events = {
    onClose: (paymentStatus) => {
        restorePage(paymentStatus);
    },
};

Успешная оплата — onPaymentSuccess

Важно

По умолчанию SDK самостоятельно обрабатывает успешную оплату и перенаправляет покупателя на redirectUrls.onSuccess из заказа, если этот адрес указан. Не переопределяйте onPaymentSuccess без необходимости.

Если вы задаете собственный обработчик, автоматическое перенаправление на redirectUrls.onSuccess отключается. В этом случае выполните переход самостоятельно:

const events = {
    onPaymentSuccess: (redirectUrls) => {
        if (redirectUrls.onSuccess) {
            window.location.assign(redirectUrls.onSuccess);
        }
    },
};

Клиентские события предназначены для управления интерфейсом и не заменяют серверную проверку статуса заказа и обработку уведомлений о платеже.

Следующая