Азия: провайдеры и банки
Это примеры, а не готовые пакеты
Эта страница показывает, как можно самостоятельно подключить этих провайдеров. Готовые пакеты есть только для Stripe, Adyen и PayPal — см. список пакетов. Если провайдер здесь упомянут, это не значит, что checkout kit уже его поддерживает.
English version: asia.md
Сначала прочитайте Настоящие провайдеры на нашем контракте.
Как устроен регион
Азия — это место, где чекаут «под карту» перестаёт работать. В Китае платят через Alipay и WeChat Pay. В Индии UPI проводит больше транзакций, чем карты. В Индонезии, Таиланде и Вьетнаме правят QR-стандарты и банковские переводы; в Японии до сих пор обычное дело — оплата в круглосуточном магазине и списание со счёта мобильного.
Почти всё это укладывается в две формы:
- Передача в приложение. На телефоне открываем платёжное приложение по диплинку. Покупатель подтверждает там и возвращается.
- Показать код и ждать. На десктопе показываем QR, который покупатель сканирует телефоном. Перенаправлять некуда, собирать с него нечего.
Первое ложится на действие redirect, второе — на display. Про оба написано ниже на этой странице.
Карта
| Провайдер | Где | Схема | Действие |
|---|---|---|---|
| Alipay / Alipay+ | Китай и трансгранично | код заказа, затем опрос | display + опрос |
| WeChat Pay | Китай | prepay id, QR или JSAPI | display + опрос |
| Razorpay | Индия | order + checkout SDK | sdk_handoff |
| PayU India, Paytm | Индия | hosted page или SDK | redirect / sdk_handoff |
| UPI | Индия | диплинк или QR | redirect / показ |
| Midtrans, Xendit | Индонезия | транзакция + перенаправление или VA | redirect / показ |
| Omise, 2C2P | Таиланд, ЮВА | токен + charge, PromptPay QR | sdk_handoff / показ |
| GrabPay, ShopeePay | ЮВА | заказ + диплинк | redirect |
| Toss, KakaoPay | Корея | ready + перенаправление + approve | redirect |
| PayPay, Komoju, GMO | Япония | перенаправление или оплата в магазине | redirect / показ |
| Stripe, Adyen | JP, SG, HK, AU | как везде | redirect / sdk_handoff |
Razorpay (Индия)
Самая частая интеграция в Индии и чистый sdk_handoff.
Бэкенд создаёт заказ. Браузер открывает чекаут Razorpay с этим id, покупатель платит через UPI, карту, нетбанкинг или кошелёк, и SDK отдаёт три поля:
action: {
id: order.id,
kind: 'sdk_handoff',
purpose: 'authorize',
surface: 'none',
sdk: 'razorpay',
scriptUrl: 'https://checkout.razorpay.com/v1/checkout.js',
completion: { via: 'sdk_callback' },
params: { key: ctx.config.keyId, orderId: order.id, amount: intent.amount },
}Адаптер открывает окно оплаты и возвращает то, что пришло в handler:
{
razorpay_payment_id: 'pay_29QQoUBi66xm2f',
razorpay_order_id: 'order_9A33XWu170gUtm',
razorpay_signature: '9ef4dffbfd84f1318f6739a3ce19f9d85851857ae648f114332d8401e0949a3d',
}Эта подпись — весь смысл, и проверять её надо на сервере. Это HMAC от order_id|payment_id с вашим key secret. Плагин проверить её не может: секрета у него нет и быть не должно. Поэтому resume отправляет все три поля на бэкенд и возвращает то, что ответит бэкенд:
resume: async (intentId, evidence, opts) => {
if (evidence.via !== 'sdk_callback') return unsupported(evidence)
return toResult(await http.post(`/razorpay/orders/${intentId}/verify`, evidence.payload, opts))
}Это самый наглядный пример правила «evidence — подсказка» во всём репозитории: у браузера на руках подписанное сообщение, и решает всё равно сервер.
Midtrans и Xendit (Индонезия)
Оба дают URL страницы оплаты — redirect + surface: 'top' + return_url, — и оба предлагают виртуальные счета: покупателю выдают номер счёта, на который он переводит деньги, возможно завтра. Виртуальный счёт — это сценарий «показать и ждать», как и QR.
Проще всего начать с invoice API у Xendit: создать инвойс, перенаправить на invoice_url, а в resume прочитать его статус.
Omise и 2C2P (Таиланд и ЮВА)
Omise токенизирует карту своим JavaScript (sdk_handoff, результат — токен, списание на бэкенде) и предлагает PromptPay как QR — снова «показать и ждать».
2C2P — история для крупного бизнеса и обычно hosted page: redirect + return_url.
Toss Payments и KakaoPay (Корея)
У корейских API схема из трёх шагов: ready, approve, confirm.
- Бэкенд вызывает «ready» и получает адрес.
- Покупателя перенаправляют туда, он подтверждает.
- Он возвращается с ключом, и бэкенд вызывает «approve» с этим ключом.
Это ложится на redirect + return_url, а resume делает approve. Как и с PayPal, деньги двигает именно approve, поэтому сам по себе возврат на вашу страницу ничего не доказывает.
Alipay и WeChat Pay (Китай)
Со стороны продавца оба работают одинаково. Вы создаёте заказ и получаете код — QR для десктопа или диплинк для телефона. Покупатель платит в приложении. Бэкенд узнаёт об этом вебхуком, а если вебхук не пришёл — опрашивает API проверки статуса.
Для диплинка плагин уже сегодня умеет всё нужное:
action: {
id: order.id,
kind: 'redirect',
purpose: 'authorize',
surface: 'top',
url: order.deepLink, // на телефоне откроет приложение
method: 'GET',
completion: { via: 'return_url' },
}Про QR — см. «Показать код и ждать» ниже.
Учтите ещё, что покупатель может вообще не вернуться на вашу страницу: он платит в приложении и переключается дальше. Платёж при этом состоялся. Ещё одна причина, почему исход должен приходить от вашего API, а не от того, что браузер вернулся.
Показать код и ждать
Так платит бо́льшая часть Азии — Alipay, WeChat, PromptPay, UPI QR, индонезийские виртуальные счета, — а ещё PIX в Бразилии и BLIK в Польше. В контракте для этого есть свой вид действия:
{
id: intentId,
kind: 'display',
surface: 'inline',
format: 'qr', // или 'code', или 'instructions'
value: '00020126...', // сам payload, всегда — см. ниже
imageUrl: qrFromProvider, // необязательно: своего кодировщика QR в наборе нет
deeplink: 'upi://pay?...',// необязательно: открывает приложение на телефоне
completion: { via: 'poll', intervalMs: 2000, timeoutMs: 15 * 60 * 1000 },
}Движок показывает это и одновременно опрашивает ваш getIntent. Кто закончил первым — останавливает другого: покупатель может уйти, а истёкший код перестаёт опрашиваться. Если выиграл опрос, вызывается resume с evidence { via: 'poll' } и перечитывает исход у вас.
Два момента:
valueзаполняйте всегда. Покупатель, читающий страницу с телефона, не отсканирует собственный экран — код для копирования тут важнее самого QR.- Ставьте свои таймауты. QR или виртуальный счёт живут часами, и движок слушает
timeoutMsиз действия, а не своё значение по умолчанию.
@checkout-kit/provider-bank-transfer — рабочий плагин такой формы, и по нему гоняются те же тесты Playwright.
На телефоне диплинк обычно удобнее QR: для него по-прежнему подходит redirect с surface: 'top', и провайдеры, у которых есть оба варианта, дают URL для одного и payload для другого.
Банки в Азии
Прямые интеграции слишком разные, чтобы обобщать, но три вещи встречаются постоянно:
- Банковский перевод с номером-ссылкой. Покупатель переводит вручную и указывает код. «Показать и ждать», причём ждать можно сутки.
- Локальные карточные схемы. RuPay в Индии, JCB в Японии, UnionPay по всему региону. Для контракта это обычные карты; меняется то, какие BIN принимает ваш PSP и какая у них аутентификация.
- Региональный 3-D Secure. У RuPay и UnionPay свои схемы аутентификации, но и они сводятся к «отправь что-то на URL и получи вердикт» — то есть к действию
redirectс завершением черезpost_messageилиreturn_url.
Что стоит знать на практике
Валюты без копеек. У японской иены, корейской воны и вьетнамского донга нет минорной единицы. amount: 1000 — это ¥1000, а не ¥10.00. Ошибка здесь стократная, и это самый частый баг в первой азиатской интеграции.
Покупатель может не вернуться. Сценарии на телефоне часто заканчиваются в другом приложении. Никогда не завязывайте финальный статус на возврат браузера.
Таймауты длиннее. QR или виртуальный счёт могут жить часами. У движка таймаут опроса по умолчанию — минута; для страницы чекаута это правильно, а для всего платежа нет: покупатель должен иметь возможность уйти, а бэкенд — сообщить исход позже.