Skip to content

Работа в браузере и восстановление ​

English

@checkout-kit/runtime-browser выполняет в браузере дополнительные шаги (действия) оплаты: открывает страницу банка, показывает QR-код, запускает SDK провайдера.

Кто за что отвечает:

  • движок следит за попыткой оплаты;
  • раннеры из этого пакета выполняют шаги и сообщают, что произошло;
  • провайдер и ваш сервер решают, прошла ли оплата на самом деле.

Установка из npm ​

sh
npm install @checkout-kit/core @checkout-kit/runtime-browser

Пакет в npm · Все варианты установки

Настройка один раз ​

ts
import { createBrowserRuntime } from '@checkout-kit/runtime-browser'
const runtime = createBrowserRuntime({ returnPath: '/checkout/payment/return' })
// Give createCheckout runtime.runners, runtime.storage and runtime.returnUrl.
  • returnPath — страница, на которую покупатель возвращается после перенаправления. Если сайт открыт из подпапки, укажите её тоже. Путь добавляется к адресу текущего сайта.
  • Всегда передавайте движку runtime.storage. Хранилище движка по умолчанию живёт в памяти и пропадает, когда браузер уходит на другую страницу.

Какие шаги поддерживаются и что нужно для каждого:

ДействиеЧто происходитЧто нужно на вашей странице
redirectОткрывает адрес (GET или POST) во фрейме или во всём окне. Сохраняет адрес и поля формы.Для фрейма — место для показа. Для всего окна — рабочая страница возврата.
collect_fieldsФрейм провайдера принимает данные карты и присылает токен (через postMessage).Место для показа и точный источник (origin) фрейма.
sdk_handoffВызывает зарегистрированный адаптер SDK. Может сам загрузить скрипт SDK.Адаптер, имя которого совпадает с action.sdk.
displayПоказывает QR-код, код оплаты или инструкцию, пока движок проверяет статус.Место для показа. По желанию — адрес картинки QR от провайдера.

Без React создайте место для показа сами через createMount(element) и передайте его в engine.runPendingAction({ mount }). В React используйте PaymentActionHost. Готового раннера для всплывающих окон (popup) нет; если он нужен, зарегистрируйте свой.

SDK провайдеров ​

ts
const runtime = createBrowserRuntime({
  returnPath: '/checkout/return',
  sdk: {
    adapters: [
      {
        sdk: 'merchant-wallet',
        async request(params, signal) {
          return walletSdk.requestPayment(params, { signal })
        },
      },
    ],
  },
})

walletSdk пишете вы. Возвращайте результат после того, как SDK закончил работу, а не в момент, когда его компонент появился на экране. Для Stripe есть готовый адаптер SDK. Для Adyen адаптер возвращает дополнительные данные, которые запрашивает провайдер.

Если один и тот же адрес скрипта загружают из двух мест, он загружается один раз. Если при этом указаны разные хеши целостности (integrity), загрузка отклоняется. Раннер перестаёт ждать по истечении срока или при отмене оплаты. При отмене ваш код тоже должен закрыть окно SDK.

Восстановление после перенаправления ​

На странице возврата настройте движок так же (те же провайдеры, то же хранилище) и вызовите:

ts
const result = await engine.hydrate(runtime.readReturnParams())

Что делает hydrate:

  1. Читает сохранённые провайдер, id платежа и id шага.
  2. Спрашивает у провайдера настоящий статус заказа.
  3. Если платёж уже в окончательном статусе, больше ничего не отправляется — ни повторного подтверждения, ни повторного списания.

Данные из адреса принимаются, только если они относятся к сохранённому шагу. Если сервер временно недоступен, сохранённые данные не удаляются: вызовите hydrate позже с теми же параметрами.

Требования:

  • приложение должно открываться ровно по адресу возврата;
  • не удаляйте параметры адреса и данные session storage, пока восстановление не закончилось;
  • если покупатель вернулся в другой вкладке или в системном браузере телефона, сохранённых данных там нет, и восстановлением должно заниматься само приложение.

Попытки, повторы и отмена ​

СитуацияЧто делать
Нет ответа при создании или подтвержденииПовторите ту же попытку с тем же ключом. Движок найдёт уже созданный платёж.
Платёж в обработкеПродолжайте проверять тот же платёж. Если время вышло, результат остаётся неизвестным — не списывайте повторно.
Провайдер явно отказал или отменилСледующая попытка может создать новый платёж с новым ключом.
Начать зановоreset() очищает состояние страницы. Списание на сервере он не отменяет.
Покупатель отменяет оплатуabort() останавливает работу и просит провайдера отменить платёж, если тот это поддерживает.
Платёж прошёл во время отменыОставьте «успешно». Интерфейс не может отменить настоящий платёж.

Даже если создание платежа прервалось раньше, чем на страницу пришёл какой-либо id, движок сохраняет ключ и использует уже созданный платёж. Ваш сервер должен выполнять каждую операцию только один раз на ключ и менять состояния атомарно (целиком или никак). Выдавайте заказ по подтверждённому статусу, сохранённому на сервере, — это должно работать, даже если покупатель закрыл браузер.

Что хранится и какие сообщения принимаются ​

В session storage хранится только то, что нужно для продолжения: id. Там никогда нет полей карты, данных SDK или клиентских секретов. Если пишете свой StorageAdapter, реализуйте read, write и remove и не смешивайте разные сессии.

Сообщение из фрейма принимается, только если совпадают отправитель, источник (origin), тип сообщения и id шага. То, что покупатель скопировал или отсканировал код, не доказывает оплату: шаг display завершается только через проверку статуса. Если копирование в буфер обмена не сработало, покупатель может скопировать код вручную. Закончив работу, раннеры удаляют свои элементы, обработчики событий и таймеры.

Раздел WebView — про мобильные приложения и deep link. Решение проблем поможет, если нет места для показа шага, SDK не отвечает или восстановление не удаётся.

Правила безопасности для адресов ​

  • Адреса шагов должны использовать HTTPS.
  • Скрипты SDK провайдеров загружаются только с источников из списка security.scriptOrigins.
  • Для ссылок на банковские приложения со своей схемой (например, mybank://) нужен security.deeplinkProtocols.
  • Обычный HTTP разрешён только для localhost при разработке, с security.allowInsecureLocalhost: true.
  • Адрес возврата должен принадлежать вашему сайту.
  • По возможности подключайте SDK провайдера как пакет, а не загружайте скрипт.

Как настроить эти правила и обновить старый код.

Apache-2.0 · Headless-движок, адаптеры провайдеров и запускаемые примеры.