Refund — это не кнопка, а отдельная зона боевых действий в платежной логике
Возврат ломает не фронт, а весь ваш стек: ордера, биллинг, склад, CRM, антифрод и бухгалтерию. Один платеж можно авторизовать, потом захолдить, потом частично вернуть, потом добить вторым рефандом. Если у вас это не описано как state machine, а живет в виде «ну тут просто минусуем сумму» — поздравляю, у вас не система, а костыль на костыле и финтехом погоняет.
Что должно быть обязательно:
— отдельный refund_id и связь с original payment_id;
— идемпотентность на каждый запрос, иначе двойной рефанд обеспечен;
— статусы отдельно от платежа: pending, succeeded, failed, reversed;
— разруливание partial refund, когда сумма меньше исходной;
— асинхронные вебхуки, потому что провайдеры любят отвечать «успех» и потом молча падать.
Самая частая ошибка — считать refund финальным событием. Нет. Это процесс с задержками, ручными откатами, расхождениями по сеттлменту и веселыми кейсами, когда деньги ушли, а у вас в базе все еще «обрабатывается». Документация — это ложь, логи — истина. И если логи не позволяют восстановить цепочку событий по одному payment_id, то вы уже проиграли аудит и поддержку.
Отдельно проверьте права на возврат: не каждый менеджер должен иметь кнопку «вернуть все». Иначе одна паника, один дубль в CRM — и ваш мерчант забанен без объяснения причин со стороны провайдера.
Делайте refund как отдельный workflow, а не как побочный эффект оплаты. Идемпотентность или смерть.
Интеграция платежных решений
@payment_integration_ops_arb
Refund — это не кнопка, а отдельная зона боевых действий в платежной логике
Этот пост опубликован в Telegram-канале Интеграция платежных решений. Подписаться можно по ссылке: @payment_integration_ops_arb.