Архитектура интеграции платежей: карты, кошельки, счета и статусы заказов
Создание унифицированной архитектуры интеграции платежей, которая обрабатывает карты, цифровые кошельки, счета и отслеживание статусов заказов. Технические инсайты и реальные компромиссы.

Интеграция платежей редко сводится к простому подключению одного SDK. В наших проектах в DigiForge мы видели, как проекты раздувались, потому что команды недооценивали сложность обработки нескольких способов оплаты — карт, цифровых кошельков, оплаты по счетам — и последующей привязки их к жизненному циклу заказа. Каждый тип платежа имеет свои особенности, и их объединение без целостной архитектуры приводит к хрупкому коду и мучительной сверке. В этой статье разбирается, как выглядит единый слой интеграции платежей, основанный как на устоявшихся паттернах, так и на новых разработках, таких как карты с поддержкой стейблкоинов.
Карты: Токенизация, сетевые токены и рост карт с поддержкой стейблкоинов
Карточные платежи остаются основой электронной коммерции и многих SaaS-бизнесов. Золотое правило — никогда не обрабатывать номера карт в открытом виде. Токенизация через PCI-совместимый шлюз (Stripe, Braintree, Adyen) — это минимальный стандарт. Но есть и более тонкий слой: сетевые токены. Это привязанные к устройству одноразовые токены, выпускаемые самими карточными сетями, которые обеспечивают более высокий процент авторизации и снижают мошенничество. Мы обычно рекомендуем клиентам внедрять сетевую токенизацию на ранних этапах, особенно если они обрабатывают регулярные платежи, поскольку срок жизни токенов дольше, а обновления обрабатываются сетью.
Новая волна — это карты с поддержкой стейблкоинов. По состоянию на конец 2025 года объем операций по криптокартам достиг $18 млрд в годовом исчислении, увеличиваясь на 106% ежегодно с 2023 года (пресс-релиз Wirex/Crossmint). Архитектура здесь иная: вместо списания с банковского счета или кредитной линии карта использует кошелек со стейблкоинами. Для разработчиков это означает интеграцию с провайдером кошельков (например, смарт-кошелек Crossmint) и эмитентом карт (например, Wirex). Сложность заключается в соблюдении требований — в пресс-релизе отмечается, что ранее финтех-компаниям приходилось собирать кошелек, эмитента и нормативную базу по отдельности. В DigiForge мы работали над подобными мультивендорными интеграциями и обнаружили, что слой абстракции с унифицированной моделью транзакций необходим. Иначе отладка неудачного платежа превращается в погоню за информацией по трем панелям провайдеров.
Цифровые кошельки: UPI, Google Pay и интеграция через хостинг или API
Цифровые кошельки не являются монолитными. Google Pay (теперь часть более широкой экосистемы Google Payments) работает иначе, чем индийские кошельки на базе UPI, такие как Paytm, и оба отличаются от кошельков конкретных приложений. Архитектурное решение заключается в выборе между хостированным чек-аутом (проще, меньше контроля) и интеграцией через API (сложнее, богаче пользовательский опыт).
Для кошельков, таких как Google Pay, Apple Pay и PayPal, распространенным паттерном является кнопка кошелька, которая открывает панель или перенаправляет. Интеграция обычно выполняется через унифицированный чек-аут платежного шлюза — например, Stripe Payment Element автоматически отображает все кошельки. Во многих случаях этого достаточно, но мы сталкивались с ограничениями, когда требуется кастомная стилизация или сбор дополнительных данных перед оплатой. Более глубокая интеграция через собственный SDK кошелька дает больше контроля, но обязывает поддерживать отдельные ветки кода.
Кошельки на базе UPI, такие как Paytm, работают иначе. UPI (Unified Payments Interface) — это система мгновенных платежей, позволяющая осуществлять прямые переводы между банками. При интеграции Paytm как способа оплаты типичный поток выглядит так: пользователь выбирает Paytm, бэкенд генерирует платежный запрос, пользователь авторизует его в приложении Paytm, и Paytm отправляет колбэк. Проблема здесь — идемпотентность: UPI-платежи могут успешно пройти на стороне банка, но сообщить об ошибке мерчанту из-за сетевых тайм-аутов. Мы всегда создаем задачу сверки, которая сравнивает статус нашего заказа со статусом транзакции Paytm каждые несколько минут.
Один паттерн, который мы нашли надежным: рассматривайте каждый платеж через кошелек как двухфазный коммит. Первая фаза создает ожидающий заказ, вторая подтверждает через вебхук. Никогда не помечайте заказ как завершенный только на основе колбэка перенаправления.
Счета: Платежные запросы и сверка
Инвойсовые платежи — когда бизнес выставляет счет, а клиент оплачивает его позже — порождают другой набор проблем. Страница IRS Payments (irs.gov/payments) является примером крупномасштабной системы выставления счетов: вы проверяете свой баланс (через уведомление или онлайн-аккаунт), а затем оплачиваете с помощью банковского счета (Direct Pay) или плана рассрочки. Архитектура должна обрабатывать как жизненный цикл счета (выставлен, отправлен, просрочен, оплачен), так и жизненный цикл платежа (инициирован, в обработке, завершен, отклонен).
Для B2B SaaS или пользовательских веб-приложений мы часто создаем модуль выставления счетов, который генерирует PDF-файлы и размещает платежный портал. Портал должен принимать несколько способов оплаты: карта, кошелек или банковский перевод. Хитрость заключается в том, чтобы связать ID счета с ID транзакции платежа в шлюзе, а затем использовать вебхуки для обновления статуса счета. Распространенная ошибка — полагаться на встроенную функцию выставления счетов платежного шлюза, но потерять контроль над сверкой. Мы предпочитаем хранить собственные записи счетов и использовать шлюз только как платежный процессор.
// Example webhook handler for invoice payment confirmation
app.post('/webhooks/stripe', async (req, res) => {
const event = req.body;
if (event.type === 'checkout.session.completed') {
const session = event.data.object;
const invoiceId = session.metadata.invoice_id;
await db.invoices.update({ id: invoiceId }, { status: 'paid' });
}
res.json({ received: true });
});
Приведенный выше код упрощен, но иллюстрирует основную идею: сопоставить событие шлюза с вашей собственной доменной моделью. Поле metadata — ваша спасательная соломинка. Без него вам пришлось бы запрашивать Stripe для сопоставления сессий, что добавляет задержки и сложности.
Статус заказа: сопоставление платежных событий с жизненным циклом
Заказ может проходить через множество статусов: pending_payment, payment_received, processing, fulfilled, cancelled. Событие оплаты должно быть лишь одним из многих триггеров. Ключевое архитектурное решение — использовать конечный автомат или более простое поле статуса. Мы настоятельно рекомендуем конечные автоматы для систем с более чем четырьмя статусами или со сложными переходами (например, заказ может перейти из 'payment_received' в 'processing', затем в 'shipped', но также из 'pending_payment' в 'cancelled'). Хорошо подходят гем StateMachines для Rails или собственный конечный автомат на Node.js.
Вебхуки от платежных шлюзов должны напрямую подаваться в конечный автомат. Например, событие payment_intent.succeeded должно переводить заказ из 'pending_payment' в 'payment_received'. Но нужно защититься от состояний гонки: если вебхук приходит дважды (большинство шлюзов гарантируют доставку хотя бы один раз), ваш конечный автомат должен быть идемпотентным — то есть переход из того же текущего состояния в то же следующее состояние должен быть холостым. Мы храним event_id для каждого вебхука для дедупликации.
Идемпотентность не является опциональной. Если ваш обработчик вебхуков оплаты не идемпотентен, вы в конечном итоге дважды спишете средства с клиента или создадите заказы-призраки. Тестировать это при нормальной нагрузке сложно; мы имитируем задержанные и дублированные вебхуки в нашем CI-конвейере.
Статус заказа также должен быть доступен клиентам. Простая страница статуса (например, индикатор выполнения) работает, но только если базовые переходы точны. Мы видели системы, где фронтенд опрашивает API, кэширующее статус заказа — но кэш может быть устаревшим, если вебхук еще не обработан. Решение — использовать канал реального времени (WebSocket или Server-Sent Events), который отправляет изменения статуса, чтобы интерфейс обновлялся сразу после обработки вебхука. Для более простых проектов допустим кэш с коротким временем жизни (TTL 30 секунд).
Мнение DigiForge: Стройте слой интеграции платежей, а не бардак
После интеграции десятков платежных методов в различных проектах наш совет — абстрагировать обработку платежей за тонким сервисным слоем. Этот слой должен нормализовать события каждого платежного провайдера в общий формат событий, обрабатывать повторные попытки и вести журнал транзакций. Система заказов никогда не общается напрямую со Stripe, Paytm или любым другим эмитентом — она общается с вашим платежным сервисом. Это значительно упрощает добавление новых способов оплаты (например, карты на стейблкоинах) без изменения логики заказов.
Мы также рекомендуем рассматривать счета как отдельный домен, а не просто статус заказа. Счет имеет свой собственный жизненный цикл (черновик, отправлен, просрочен, оплачен) и может быть связан с несколькими заказами (например, ежемесячная подписка). Аналогично, статус заказа должен управляться конечным автоматом, который обрабатывает все возможные переходы, включая частичные платежи, возвраты и чарджбэки.
Если вы создаете платежную интеграцию с нуля, начните с составления карты всех платежных методов, которые планируете поддерживать, и определите общие события, которые они генерируют. Затем спроектируйте конечный автомат и обработчик вебхуков. Если это сделано правильно, остальное — дело техники. Если вам нужно второе мнение по вашей архитектуре, команда DigiForge видела достаточно крайних случаев, чтобы сэкономить вам несколько бессонных ночей.
Источники
- Wirex and Crossmint Announce Card Integration to Connect Stablecoin Wallets and Real-World Spending
- Wirex and Crossmint Announce Card Integration to Connect Stablecoin Wallets and Real-World Spending
- payments.google.com
- Payments | Internal Revenue Service
- Paytm: Secure & Fast UPI Payments, Recharge Mobile & Pay Bills


