---
metadata:
  - name: generator
    content: Diplodoc Platform v5.66.1
alternate:
  - https://pay.yandex.ru/docs/ru/custom/web-sdk/pay-widget.md
  - href: https://pay.yandex.ru/docs/ru/custom/web-sdk/pay-widget.md
    type: text/markdown
    title: Markdown version
  - href: https://pay.yandex.ru/docs/ru/llms.txt?revision=r22066231
    rel: describedby
title: Виджет оплаты Яндекс Пэй — подключение и запуск оплаты | Документация
description: Подключение платежного виджета Яндекс Пэй, обновление данных виджета, запуск оплаты и обработка событий.
---
> **Documentation Index:** Fetch the complete configuration index at https://pay.yandex.ru/docs/ru/llms.txt?revision=r22066231


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

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

![Виджет оплаты](./_assets/widgets/pay-widget-web.png){.c-screenshot width=450px}

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

- [Merchant ID](https://pay.yandex.ru/docs/ru/console/settings-pay-split.md#merchant-id) (`merchantId`) из личного кабинета Яндекс Пэй;
- настроенная [интеграция с Yandex Pay API](https://pay.yandex.ru/docs/ru/custom/back-index.yaml);
- платежная ссылка, которую ваш сервер получает при создании заказа;
- HTML-контейнер для виджета.

{% note warning %}

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

{% endnote %}

## Шаг 1. Подключите SDK {#include-sdk}

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

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

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


```

{% note warning %}

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

{% endnote %}

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

```javascript
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();
}
```

{% note info %}

Сайт должен работать по HTTPS. Требования к CSP и другим заголовкам безопасности приведены в разделе [Требования к подключению](https://pay.yandex.ru/docs/ru/custom/web-sdk/index.md#requirements).

{% endnote %}

## Шаг 2. Подготовьте данные платежа {#payment-data}

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

```javascript
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` | Количество товара в виде строки. Если передано, значение должно быть больше нуля. |

{% note warning %}

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

{% endnote %}

## Шаг 3. Создайте сессию и разместите виджет {#mount-widget}

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

```javascript
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`                    | Темная тема   ||
|#

{% note warning %}

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

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

{% endnote %}

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

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

```javascript
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. Запустите оплату {#start-payment}

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

```javascript
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 после создания заказа на сервере продавца.

## Обработка ошибок {#errors}

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

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

## События виджета {#events}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

{% note warning %}

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

{% endnote %}

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

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

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