Сервер мерчанта
В примере HTTP-сервера уже есть маршруты для Stripe, Adyen и PayPal. Сначала запустите его у себя. Потом, для настоящего магазина, замените хранение в памяти и упрощённые сессии на свою систему заказов и вход пользователей.
Режимы и настройки
Запустить можно двумя способами:
npm run dev:integrationзапускает сервер с локальными поддельными провайдерами и React-приложение;npm run dev:server -w @checkout-kit/examplesобращается к настоящим тестовым API (песочницам) тех провайдеров, для которых указаны ключи.
Провайдер без ключей отключается. По адресу /health видно, в каком режиме работает сервер.
| Где | Переменная | Что это |
|---|---|---|
| Сервер | PORT, CHECKOUT_HOST | Порт и адрес, на котором слушает сервер. По умолчанию 4000 и 127.0.0.1. |
| Сервер | CHECKOUT_ORIGIN | Адрес веб-приложения, обычно http://localhost:5173. |
| Сервер | CHECKOUT_RETURN_URL | Страница возврата после перенаправления, обычно http://localhost:5173/payment/return. |
| Сервер | STRIPE_SECRET_KEY | Тестовый секретный ключ Stripe. |
| Сервер | ADYEN_API_KEY, ADYEN_MERCHANT_ACCOUNT | Тестовый аккаунт Adyen. |
| Сервер | ADYEN_WEBHOOK_HMAC_KEY | Ключ для проверки, что уведомления Adyen настоящие. |
| Сервер | PAYPAL_CLIENT_ID, PAYPAL_CLIENT_SECRET | Приложение PayPal в песочнице. |
| Браузер | VITE_REAL_PROVIDER_API_BASE_URL | Адрес API вашего сервера, обычно http://localhost:4000. |
| Браузер | VITE_STRIPE_PUBLISHABLE_KEY, VITE_ADYEN_CLIENT_KEY | Публичные тестовые ключи для полей карты и шагов SDK. |
Открывайте приложение и API на одном имени хоста. Иначе браузер не отправит cookie входа (из-за SameSite=Lax). Переменные браузера видны всем; секретные ключи должны оставаться на сервере. Дальше следуйте руководству своего провайдера.
Маршруты сервера
| Маршрут | Что делает |
|---|---|
/stripe/payments | Создать, подтвердить, прочитать и отменить PaymentIntent в Stripe. |
/adyen/payments/sessions | Зарезервировать заказ для Adyen Advanced flow. |
/adyen/payments/:id, /:id/details, /:id/cancel | Отправить данные компонента и доп. данные, прочитать статус, запросить отмену. |
/adyen/webhooks | Проверить и применить уведомления Adyen. |
/paypal/orders, /:id, /:id/capture | Создать, прочитать заказ PayPal и списать по нему деньги (Orders v2). |
Защита от повторных запросов. Каждый JSON-запрос, который меняет данные, отправляется с заголовком Idempotency-Key. Пример запоминает результат для пары «сессия + метод и путь»:
- если одновременно пришли два одинаковых запроса, оба получат один и тот же результат;
- если пришёл запрос с тем же ключом, но другими данными, сервер отвечает 409;
- ключи, которые передаются провайдеру, привязываются к сессии и хешируются.
Сервер игнорирует сумму и адрес возврата, присланные браузером, и использует только свои значения.
Изоляция. Заказ принадлежит одной серверной сессии. Другая сессия не может его прочитать или изменить. В примере для этого используется cookie со случайным UUID. Он лишь показывает разделение и не является настоящим входом пользователя.
Что заменить в настоящем магазине
| В примере | В вашем приложении |
|---|---|
| Заказы в памяти | База данных с ценой, покупателем, id платежа у провайдера и записями оплат. |
| Cookie сессии с UUID | Настоящий вход, сессии и защита от CSRF. |
| Защита от повторов в памяти | Сохранённый ключ, отпечаток запроса и атомарная блокировка с сохранённым результатом. |
Локальный каталог 1id / 2id | Ваш настоящий каталог товаров и заказов. |
| Данные шагов в памяти | Сохранённые данные с контролем доступа, которые переживают перезапуск и перенаправление. |
| Проверка статуса из браузера | Сверка на сервере и проверенные уведомления, даже после закрытия браузера. |
Сохраняйте решение и его результат вместе, одной операцией. Если сеть оборвалась и непонятно, выполнилась ли операция, оставьте тот же ключ операции. Подтверждение, списание, отмена и обновление по вебхуку должны менять состояние атомарно, даже если одновременно работает несколько серверных процессов.
Уведомления и выдача заказа
Для уведомлений Adyen пример:
- проверяет подпись официальным HMAC-валидатором;
- проверяет аккаунт мерчанта, сумму и валюту;
- пропускает более старые события;
- отклоняет весь пакет, если хоть один элемент неверный (ничего не применяется частично).
В своём приложении храните порядок событий и историю повторов в базе данных.
Для Stripe и PayPal пример читает статус, когда об этом просит браузер. Ваше приложение должно проверять платежи и без браузера (покупатель может не вернуться) и выдавать заказ только по подтверждённому статусу на сервере. Политика списания должна соответствовать тому, как вы трактуете результаты. Событие «успешно» в интерфейсе — только чтобы показать сообщение или перейти на следующую страницу.
Проверьте свой сервер
Проверьте случаи: оплачено, отказ, в обработке, доп. проверка / перенаправление, повторный и изменённый запрос, потерянный ответ, чужая сессия, неверные данные в вебхуке, восстановление после сбоя. Используйте тестовые данные и браузерные тесты и свой настоящий тестовый аккаунт.