Один провайдер ляжет — и вы узнаете об этом в пятницу вечером. Разбираем архитектуру платёжной интеграции для high-risk бизнесов: каскад провайдеров, машина состояний, идемпотентность и грамотные retry-стратегии.
Почему платёжная архитектура в high-risk — отдельная дисциплина
Если ваш бизнес попадает в категорию high-risk — крипто-обменник, P2P-сервис, подписка с триалом, форекс или iGaming — вы уже знаете: стандартный эквайринг либо не берёт вас совсем, либо берёт, а потом замораживает деньги без предупреждения. Stripe, Adyen и им подобные вежливо проводят пару месяцев транзакций, а затем шлют письмо в пятницу вечером. MID перестаёт принимать платежи, выручка за последнюю неделю зависает, а onboarding у резервного эквайера занимает шесть недель.
Из этого простого факта вырастает вся архитектура, о которой пойдёт речь ниже. Не теория из учебника — а то, что реально держит системы в проде, когда с них списываются живые деньги.
Главные боли: фрод, чарджбеки и внезапные отключения
В high-risk вертикалях три постоянных источника потерь.
- Card testing. Боты прогоняют через платёжную форму сотни краденых карт мелкими суммами — проверяют, какие живые. Каждая такая авторизация портит вашу статистику у эквайера, даже если деньги не списались. Для крипто-обменника или P2P-сервиса это прямой удар по рейтингу мерчанта.
- Чарджбеки. Порог у Visa и Mastercard — около 0,9–1% от оборота. Превысили — попадаете в monitoring program со штрафами. Не исправились — расторжение договора и запись в MATCH-лист на пять лет. Для платёжного бизнеса это не проблема, это конец.
- Внезапные отключения. Лимиты MID кончаются, банк меняет риск-аппетит, шлюз проводит техработы в три ночи. Любой провайдер может умереть сегодня — проектировать нужно именно из этого предположения.
Отдельно стоит «дружественный фрод»: клиент реально платил, но видит непонятный дескриптор в выписке и оспаривает транзакцию. Дескриптор должен совпадать с тем, что клиент видел на сайте — это скучное требование экономит больше денег, чем половина антифрод-инструментов.
Машина состояний — фундамент, а не опция
Статусы платежа должны быть явной машиной состояний, а не набором if-ов, размазанных по сервисам. Базовая цепочка выглядит так:
- Initiated → Requested → Approved → Deposited → Processed
- Declined / Unapproved / Cancelled / Reversed — финальные ветки
Три правила, которые обязательны на проде:
- Approved ≠ Charged. Деньги в холде — ещё не ваши. Засчитывать транзакцию как успешную можно только после подтверждённого списания.
- Каждый переход валидируется на сервере. Пришёл запрос на Deposit по платежу в статусе Declined — это баг или атака, а не «ну попробуем».
- Таймаут шлюза — не отказ. Платёж мог пройти на той стороне, а ответ потеряться. Единственная корректная реакция — вызвать GetPayment и узнать фактическое состояние. Считать таймаут отказом — риск двойного списания. Считать успехом — подарок фродерам.
Идемпотентность: три уровня защиты
Шлюз ретраит серверные колбэки до пяти раз, если не получил ответ за пару секунд. Ваш обработчик обязан переживать дубликаты.
- Уникальный Order.ID на каждую попытку платежа. Никогда не повторяйте потенциально успешную операцию с тем же ID — шлюз должен уметь ответить «уже проведено».
- Сырые колбэки пишутся только через INSERT. Дубликаты в этой таблице — фича, а не баг: это ваш лог для реконсиляции спорных транзакций.
- UNIQUE constraint на paymentId в таблице зачислений — последний рубеж, когда всё остальное не сработало.
Боевой кейс: зачисление средств жило в одной транзакции, а перевод платежа в финальный статус — в другой, без блокировки. Ретрай колбэка успевал проскочить в зазор: первая обработка ещё не флипнула статус, вторая видела «необработанный» платёж и зачисляла ещё раз. Двойной кредит, живые деньги. Лечится одной транзакцией на всё, SELECT ... FOR UPDATE на строку платежа и UNIQUE-ограничением на зачислении.
Сетевой вызов и транзакция БД — враги
SOAP/HTTP-вызов к шлюзу внутри транзакции БД выглядит невинно — «атомарно же». На деле, если процесс упал между вызовом шлюза и коммитом, транзакция откатилась, и в базе нет никаких следов того, что вы вообще ходили списывать деньги. Ретрай — и второе списание.
Правильная схема — три фазы: сначала INSERT попытки со статусом INTENT и коммит, затем сетевой вызов строго вне любой транзакции, затем отдельная транзакция с финальным статусом по фактическому ответу. Запись о намерении коммитится до сетевого вызова — это и есть идемпотентность на уровне списаний.
Retry-стратегии: не все отказы одинаковы
Ретраить всё подряд — самый быстрый способ испортить fraud ratio и получить вопросы от эквайера. Отказы делятся на три категории:
- Hard stop. AUTHENTICATION_DECLINED, EXPIRED_CARD, SUSPECTED_FRAUD, LOST_CARD, STOLEN_CARD — дальнейшие попытки блокируются полностью. Ретрай здесь не помогает, только вредит.
- Soft retry. TRANSACTION_DECLINED, ISSUER_UNAVAILABLE, RECONCILE_ERROR — проблема не в карте, а в состоянии системы. Подождать от 24 часов и попробовать снова.
- Изменить условия. INSUFFICIENT_BALANCE, EXCEED_AMOUNT_LIMIT — денег нет или лимит превышен. Имеет смысл изменить сумму (если соглашение позволяет) или способ оплаты, затем retry через 8–12 часов.
На практике ветка insufficient funds окупается лучше всего: у аудитории подписочных и кредитных продуктов деньги появляются волнами — зарплата, переводы. Терпеливый ретрай раз в 12 часов дособирает заметный процент выручки, который иначе просто теряется.
Мульти-PSP каскад и фолбэк
Один провайдер почти никогда не работает стабильно — и дело не в качестве конкретного PSP. Конверсия скачет по BIN-диапазонам: карты одного банка-эмитента отлично проходят через провайдера A и массово отклоняются через B. Лимиты MID конечны. Риск-аппетит эквайера меняется без предупреждения. За год в проде каждый из провайдеров хотя бы раз становился «тем самым, который лежит».
Рабочая схема строится на двух механизмах:
- Circuit breaker. Success rate в скользящем окне упал ниже порога — провайдер автоматически выключается из ротации, трафик перетекает на остальных. Возврат — тоже автоматический, через пробные транзакции. Именно это превращает «провайдер лёг в пятницу» из инцидента в строчку в отчёте.
- Failover-каскад — с жёсткими ограничениями. Каскадировать можно только системные отказы: таймаут, 5xx, превышение лимитов — и только после проверки через GetPayment, что первый провайдер реально не списал. Hard decline не каскадируется никогда. Код antifraud-блока — это сигнал «с картой что-то не так»; прогнать её тут же через второго эквайера значит перенести фрод-статистику и туда. Это самый быстрый способ потерять оба MID сразу.
Именно такую логику — маршрутизацию через пул провайдеров с автоматическим фолбэком на следующего при отказе — реализует платформа MultiFlow. Для обменников и P2P-сервисов, принимающих рубли через СБП, это означает стабильный приём без ручного переключения между провайдерами и без потери конверсии из-за отказа одного из них.
Антифрод: что реально работает
- Velocity checks. Считаем частоту попыток по карте, IP, email и device fingerprint в скользящих окнах. Больше N попыток разными картами с одного устройства за час — карантин. Именно velocity останавливает card testing, потому что боту нужны десятки попыток, а живому человеку — одна-две.
- Device fingerprinting. Задача — отличить «человек опечатался в CVV» от «один браузер перебирает двухсотую карту». Canvas, набор шрифтов, часовой пояс, поведенческие сигналы. Готовые SDK справляются с этим лучше самописных решений.
- Blacklist/whitelist. Чёрный список — хэши PAN, email и fingerprint после чарджбека или antifraud-кода от шлюза. Белый — верифицированные плательщики, которых не нужно гонять через полный скоринг. Списки без TTL и процесса разбора превращаются в свалку, которая режет конверсию. Чистка раз в квартал обязательна.
Ошибки, которые совершают почти все
- Один провайдер и «второго добавим потом». «Потом» наступает в пятницу вечером вместе с заблокированным MID, а onboarding у резервного эквайера занимает шесть недель.
- Бизнес-логика синхронно в webhook-обработчике. Шлюз ждёт ответ две секунды. Начисление бонусов, отправка писем и пересчёт статистики — в очередь, а не в обработчик.
- Ретрай hard decline. Это не «попробуем ещё раз», это способ испортить fraud ratio и потерять MID.
- Несоответствие MCC реальному бизнесу. Эквайеры ловят это быстро — и заканчивается не штрафом, а MATCH-листом.
Вывод: архитектура — это страховка от пятницы
В high-risk платёжная архитектура — это не про красивый код. Это про то, чтобы бизнес продолжал принимать деньги, когда один из провайдеров ляжет, эквайер сменит риск-аппетит или шлюз уйдёт на техработы. Машина состояний, идемпотентность, трёхфазное списание и мульти-PSP каскад — не оверинжиниринг, а минимальный набор для стабильной работы.
Если вы принимаете рубли через СБП и сталкиваетесь с отказами, нестабильной конверсией или зависимостью от одного провайдера — MultiFlow решает именно эту задачу: платформа маршрутизирует каждый платёж через пул провайдеров с автоматическим фолбэком, а вывод доступен в том числе в USDT. Подключиться можно без российского банковского эквайринга.
Материал подготовлен с помощью ИИ на основе публикации habr.com.