Refund — это не «откат платежа», а отдельная бизнес-операция с собственными граблями
Возврат ломает красивую схему «оплата → заказ → прибыль». У тебя внезапно появляются частичный refund, полный refund, возврат после сеттлмента, возврат по отменённому заказу, возврат по спору. И если это не разнесено по статусам, бухгалтерия, саппорт и антифрод начинают играть в горячую картошку.
Нормальная логика возвратов обязана жить отдельно от платежа:
— хранить исходный transaction_id, а не искать платёж по сумме;
— иметь свой статусный цикл: requested, pending, succeeded, failed, reversed;
— быть идемпотентной, иначе двойной клик саппорта превращается в двойное списание назад;
— поддерживать частичный возврат без пересчёта заказа «на коленке»;
— уметь объяснить, что делать, если деньги ещё в холде, а не в сеттлменте. Идемпотентность или смерть.
Самая мерзкая ошибка — считать refund зеркалом charge. Это ложь. У возврата другой тайминг, другой источник истины и иногда другой провайдерский маршрут. Документация это часто прячет, логи — нет: там видно, что webhook пришёл раньше, чем ты успел обновить заказ, и дальше начинается костыль на костыле и финтехом погоняет.
Отдельно проверь reconciliation: refund должен сходиться не только в CRM, но и в выписке, отчётах провайдера и внутреннем ledger. Иначе через месяц у тебя «успешный возврат» в интерфейсе и фантомная выручка в учёте.
Вывод простой: возврат проектируют как независимый процесс, а не как кнопку «минус платёж». Иначе ваш мерчант забанен без объяснения причин — только уже внутри собственной системы.
Интеграция платежных решений
@payment_integration_ops_arb
Refund — это не «откат платежа», а отдельная бизнес-операция с собственными граблями
Этот пост опубликован в Telegram-канале Интеграция платежных решений. Подписаться можно по ссылке: @payment_integration_ops_arb.